{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "33344327",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T10:00:50.366470Z",
     "start_time": "2025-06-13T10:00:50.356469Z"
    }
   },
   "source": [
    "# 版本"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "da7ed17a",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T10:11:03.472538Z",
     "start_time": "2025-06-13T10:11:03.453537Z"
    }
   },
   "source": [
    "| 软件及依赖 | 版本 |\n",
    "| :---: | :---: |\n",
    "| Anaconda | Anaconda3-2021.05|\n",
    "| conda | conda 4.10.1|\n",
    "|jupyter notebook| 6.3.0 |\n",
    "| python | Python 3.8.20 |\n",
    "| pip | 25.0.1 |\n",
    "|flask |  3.0.3 |\n",
    "|jieba | 0.42.1 |\n",
    "|matplotlib |  3.7.5 |\n",
    "|xlwt |1.3.0 |\n",
    "|wordcloud |1.9.4|"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45b7b9fe",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T15:54:47.403564Z",
     "start_time": "2025-06-11T15:54:47.391564Z"
    }
   },
   "source": [
    "# 爬取网页"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e9cc7727",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T19:44:31.597975Z",
     "start_time": "2025-06-11T19:44:31.591975Z"
    }
   },
   "source": [
    "## 获取数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dfc998a0",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T19:42:59.231692Z",
     "start_time": "2025-06-11T19:42:59.223692Z"
    }
   },
   "outputs": [],
   "source": [
    "# 定义模块get_url，功能：获取网页内容\n",
    "def get_url(url):\n",
    "    # 获取response数据，需要学习urllib库的使用\n",
    "    pass\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cfd80c1f",
   "metadata": {},
   "source": [
    "##  urllib库的使用"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12b1df4c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T08:55:01.414008Z",
     "start_time": "2025-06-11T08:55:01.402008Z"
    }
   },
   "source": [
    "### 名词解释"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3313fda9",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T08:59:26.381163Z",
     "start_time": "2025-06-11T08:59:26.366163Z"
    }
   },
   "source": [
    "| 名称 | 解释 |\n",
    "| :---: | :---: |\n",
    "| User - Agent | 用户代理：告诉服务器，我们是什么类型的机器、浏览器。告诉浏览器，我们可以接受什么样的文件内容|\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3ed76c97",
   "metadata": {},
   "source": [
    "### request使用"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "decab565",
   "metadata": {},
   "source": [
    "####  get请求"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "75cec27b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 制定url，获取网页数据\n",
    "import urllib.request"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2c4db826",
   "metadata": {},
   "outputs": [],
   "source": [
    "# get请求获取网页数据response对象\n",
    "response = urllib.request.urlopen('http://httpbin.org/get') \n",
    "response"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0f543c8a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# read() 获取response源码 二进制形式的\n",
    "data_byte = response.read()\n",
    "# 打印结果\n",
    "data_byte"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2b1fdfb4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# decode() 使用相应的字符集解码\n",
    "sourcecode = data_byte.decode('utf-8')\n",
    "sourcecode"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b614aa44",
   "metadata": {},
   "source": [
    "#### post请求的发送方式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2cd44e6d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# post请求获取源码\n",
    "# 解析数据\n",
    "import urllib.parse\n",
    "\n",
    "# 解析发送的表单数据\n",
    "## parse包装发送的数据\n",
    "data_utf8 = urllib.parse.urlencode({'username': 'password'})\n",
    "data_utf8"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ae386e52",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 设置post表单 ：转换为二进制的形式发送\n",
    "data = bytes(data_utf8, encoding='utf-8')\n",
    "data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "430a6e1b",
   "metadata": {
    "code_folding": []
   },
   "outputs": [],
   "source": [
    "# 发送post请求\n",
    "response = urllib.request.urlopen('http://httpbin.org/post',data = data)\n",
    "\n",
    "# 打印结果\n",
    "response.read().decode('utf-8')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "030006c8",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T07:35:44.285916Z",
     "start_time": "2025-06-11T07:35:44.274915Z"
    }
   },
   "source": [
    "#### 超时处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b686be4b",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T07:37:03.428443Z",
     "start_time": "2025-06-11T07:37:03.412442Z"
    }
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    pass\n",
    "except urllib.error.URLError as e:\n",
    "    pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "961766ea",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T07:43:18.673906Z",
     "start_time": "2025-06-11T07:43:18.409890Z"
    }
   },
   "outputs": [],
   "source": [
    "try:\n",
    "    # get请求获取网页数据response对象\n",
    "    response = urllib.request.urlopen('http://httpbin.org/get', timeout=0.01)\n",
    "except urllib.error.URLError as e:\n",
    "    print('请求超时')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c043ef94",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 网页url\n",
    "baseurl = 'https://movie.douban.com/top250?start='\n",
    "# 爬取网页\n",
    "datalist = getData(baseurl)\n",
    "\n",
    "# 解析数据\n",
    "\n",
    "# 保存数据\n",
    "\n",
    "## 定义网址数据\n",
    "url = 'http://www.baidu.com'\n",
    "url"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c736c6db",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T07:48:00.406020Z",
     "start_time": "2025-06-11T07:48:00.399019Z"
    }
   },
   "source": [
    "#### 响应头header"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "407d1988",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T07:50:00.599894Z",
     "start_time": "2025-06-11T07:50:00.512889Z"
    }
   },
   "outputs": [],
   "source": [
    "# get请求获取网页数据response对象\n",
    "response = urllib.request.urlopen('http://www.baidu.com')\n",
    "# 获取响应头全部数据\n",
    "response.getheaders()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "56cd1e96",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T07:56:54.068543Z",
     "start_time": "2025-06-11T07:56:54.046542Z"
    }
   },
   "outputs": [],
   "source": [
    "# 获取响应头某个信息\n",
    "response.getheader('Server')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fced0f83",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T07:58:27.815906Z",
     "start_time": "2025-06-11T07:58:27.805905Z"
    }
   },
   "source": [
    "#### 正确使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "db5f8aa6",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T08:20:12.555532Z",
     "start_time": "2025-06-11T08:20:11.937497Z"
    },
    "code_folding": [
     0
    ]
   },
   "outputs": [],
   "source": [
    "# 封装请求\n",
    "# url地址\n",
    "url = 'http://httpbin.org/post'\n",
    "# 请求头\n",
    "headers = {\n",
    "    'User-Agent':\n",
    "    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'\n",
    "}\n",
    "# 表单数据\n",
    "data = bytes(urllib.parse.urlencode({'name': 'meining'}), encoding='utf-8')\n",
    "# 发送post请求\n",
    "req = urllib.request.Request(url=url,\n",
    "                             data=data,\n",
    "                             headers=headers,\n",
    "                             method='POST')\n",
    "# 获取响应数据\n",
    "response = urllib.request.urlopen(req)\n",
    "# 解码\n",
    "response.read().decode('utf-8')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f2f98a6e",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T08:22:35.232693Z",
     "start_time": "2025-06-11T08:22:35.224693Z"
    }
   },
   "source": [
    "#### 访问豆瓣"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "87d4dbe9",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-16T15:52:01.994586Z",
     "start_time": "2025-06-16T15:52:01.810576Z"
    }
   },
   "outputs": [],
   "source": [
    "# 封装请求\n",
    "# url地址\n",
    "url = 'https://douban.com'\n",
    "# 请求头\n",
    "headers = {\n",
    "    'User-Agent':\n",
    "    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'\n",
    "}\n",
    "# 发送get请求\n",
    "req = urllib.request.Request(\n",
    "    url=url,\n",
    "    headers=headers,\n",
    ")\n",
    "# 获取响应数据\n",
    "response = urllib.request.urlopen(req)\n",
    "# 解码\n",
    "response.read().decode('utf-8')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f6cab5ec",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T08:29:50.403583Z",
     "start_time": "2025-06-11T08:29:50.393583Z"
    }
   },
   "source": [
    "#### 获取网页内容\n",
    "- [ ] 定义模块get_url，功能：获取网页内容\n",
    "- [ ] 获取response数据 \n",
    "    - [ ] 封装请求\n",
    "        - [ ] url地址\n",
    "        - [ ] 请求头\n",
    "    - [ ] 发送请求\n",
    "    - [ ] 获取响应数据\n",
    "        - [ ] 解码\n",
    "- [ ] 打印结果"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "73caa39a",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T15:50:01.057186Z",
     "start_time": "2025-06-11T15:49:59.671107Z"
    }
   },
   "outputs": [],
   "source": [
    "# 定义模块get_url，功能：获取网页内容\n",
    "def get_url(url):\n",
    "    # 获取response数据\n",
    "    ## 封装请求：\n",
    "    ### 请求头\n",
    "    headers = {\n",
    "        # 模拟浏览器头部信息，向服务器发送消息\n",
    "        'user-agent':\n",
    "        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'\n",
    "    }\n",
    "    ## 发送请求\n",
    "    req = urllib.request.Request(\n",
    "        url,\n",
    "        headers=headers,\n",
    "    )\n",
    "    ## 获取响应数据\n",
    "    ### 获取数据失败时的异常处理\n",
    "    try:\n",
    "        response = urllib.request.urlopen(req)\n",
    "        ### 解码\n",
    "        html = response.read().decode('utf-8')\n",
    "        # 3.打印结果\n",
    "        print(html)\n",
    "    except urllib.error.URLError as e:\n",
    "        if hasattr(e, \"code\"):\n",
    "            print(e.code)\n",
    "        if hasattr(e, \"reason\"):\n",
    "            print(e.reason)\n",
    "    return html\n",
    "\n",
    "\n",
    "### url地址\n",
    "url = 'https://movie.douban.com/top250?start='\n",
    "\n",
    "get_url(url)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41dcac9d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T06:59:12.221334Z",
     "start_time": "2025-06-12T06:59:12.216334Z"
    }
   },
   "source": [
    "# 解析数据"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5b96ab49",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T19:32:36.976101Z",
     "start_time": "2025-06-11T19:32:36.960100Z"
    }
   },
   "source": [
    "## 解析数据的库使用方法\n",
    "情景：\n",
    "分析网页url可知\n",
    "\n",
    "- 第一页数据url：'https://movie.douban.com/top250?start='\n",
    "- 第二页数据url：'https://movie.douban.com/top250?start=25'\n",
    "- 第三页数据url：'https://movie.douban.com/top250?start=50'\n",
    "- ...\n",
    "\n",
    "start的值变化有规律,可以用以下代码获取到\n",
    "\n",
    "`for i in range(0,8):\n",
    " start = i * 25\n",
    "`\n",
    "<br>\n",
    "i+1可以代表页数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f8d34c53",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T19:48:40.373204Z",
     "start_time": "2025-06-11T19:48:40.361204Z"
    }
   },
   "outputs": [],
   "source": [
    "# 爬取网页\n",
    "def get_data(url):\n",
    "    # 定义列表封装数据\n",
    "    datalist = []\n",
    "    # 循环获取每页数据\n",
    "    for i in range(0, 10):\n",
    "        url = url + str(i * 25)\n",
    "        # 保存获取到的网页源码\n",
    "        html = get_url(url)\n",
    "        # 逐一解析数据 需要用到BeautifulSoup库\n",
    "    pass\n",
    "\n",
    "### url地址\n",
    "url = 'https://movie.douban.com/top250?start='\n",
    "\n",
    "get_url(url)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "046a015f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T19:48:58.784257Z",
     "start_time": "2025-06-11T19:48:58.774257Z"
    }
   },
   "source": [
    "## BeautifulSoup库的使用\n",
    "将复杂的HTML文档转换成一个复杂的属性结构，每个节点都是Python对象，所有对象都可以归纳为4种：\n",
    "- Tag\n",
    "- NavigableString\n",
    "- BeautifulSoup\n",
    "- Comment"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5ccd43b8",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T23:34:59.124865Z",
     "start_time": "2025-06-11T23:34:59.110864Z"
    }
   },
   "outputs": [],
   "source": [
    "from bs4 import BeautifulSoup\n",
    "\n",
    "# 准备素材\n",
    "html = '''<!DOCTYPE html>\n",
    "\n",
    "<html> \n",
    "    <head>\n",
    "        <meta content='text/html;charset=utf-8' http-equiv='content-type' />\n",
    "        <meta content='IE=Edge' http-equiv='X-UA-Compatible' />\n",
    "        <meta content='always' name='referrer' />\n",
    "        <link href='https://ssl.bdstatic.com/5eN1jq8AAUYm2zgoY3k/r/www/cache/bdorz/baidu.min.css' rel = 'stylesheet' type = 'text/css' />\n",
    "        <title>百度一下，你就知道</title>\n",
    "    </head>\n",
    "    <body link='#0000cc'>\n",
    "        <div id = 'wrapper'> \n",
    "            <div id='head'>\n",
    "                <div class='head_wrapper'>\n",
    "                    <div id='ul'>\n",
    "                        <a class='mnav' href='http://news.baidu.com' name='tj_trnews'><!--新闻--></a>\n",
    "                        <a class='mnav' href='http://news.baidu.com' name='tj_trnews'>新闻</a>\n",
    "                        <a class='mnav' href='http://www.hao123.com' name='tj_trhao123'>hao123</a>\n",
    "                        <a class='mnav' href='http://map.baidu.com' name='tj_trmap'>地图</a>\n",
    "                        <a class='mnav' href='http://v.baidu.com' name='tj_trvideo'>视频</a>\n",
    "                        <a class='mnav' href='http://tieba.baidu.com' name='tj_trtieba'>贴吧</a>\n",
    "                        <a class='bri' href='http://www.baidu.com/more' name='tj_briicon'>更多产品</a>\n",
    "                    </div>\n",
    "                </div>\n",
    "            </div>\n",
    "        </div>\n",
    "    </body>\n",
    "</html>\n",
    "'''\n",
    "# 保存到当前目录下\n",
    "with open('./baidu.html', 'w', encoding='utf-8') as file:\n",
    "    file.write(html)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9bf5ff16",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:33:13.758113Z",
     "start_time": "2025-06-11T20:33:13.745113Z"
    }
   },
   "source": [
    "### Tag: 标签及其内容：获取它找到的第一个内容"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ca8b64f8",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T23:35:02.466056Z",
     "start_time": "2025-06-11T23:35:02.436054Z"
    }
   },
   "outputs": [],
   "source": [
    "# 打开文件\n",
    "with open('./baidu.html','rb') as file:\n",
    "    html = file.read()\n",
    "#     print(html)\n",
    "    \n",
    "# 解析数据\n",
    "bs = BeautifulSoup(html,\"html.parser\")\n",
    "# print(bs)\n",
    "print(bs.title)\n",
    "bs.a\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7ae01fab",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:40:25.098785Z",
     "start_time": "2025-06-11T20:40:25.091784Z"
    }
   },
   "source": [
    "### NavigableString :标签里的内容（字符串）"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dd4bcb02",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:38:07.717927Z",
     "start_time": "2025-06-11T20:38:07.690925Z"
    }
   },
   "outputs": [],
   "source": [
    "bs.title.string \n",
    "type(bs.title.string)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2ed7a556",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:41:45.808401Z",
     "start_time": "2025-06-11T20:41:45.792400Z"
    }
   },
   "outputs": [],
   "source": [
    "bs.a.attrs"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c7c5f69",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:43:10.561248Z",
     "start_time": "2025-06-11T20:43:10.550248Z"
    }
   },
   "source": [
    "### BeautifulSoup 表示整个文档"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1739d4ea",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:43:31.190428Z",
     "start_time": "2025-06-11T20:43:31.177428Z"
    }
   },
   "outputs": [],
   "source": [
    "type(bs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7dff08f5",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-16T16:01:58.927729Z",
     "start_time": "2025-06-16T16:01:58.861725Z"
    }
   },
   "outputs": [],
   "source": [
    "# bs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "22ed7208",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:43:58.689001Z",
     "start_time": "2025-06-11T20:43:58.672000Z"
    }
   },
   "outputs": [],
   "source": [
    "bs.name"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "01ecf3d7",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:44:08.392556Z",
     "start_time": "2025-06-11T20:44:08.378555Z"
    }
   },
   "outputs": [],
   "source": [
    "bs.attrs"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a3dcccfa",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:46:35.858991Z",
     "start_time": "2025-06-11T20:46:35.852990Z"
    }
   },
   "source": [
    "### Comment 是一个特殊的NavigableString,输出的内容不包含注释符号"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2c55f04e",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:47:45.316964Z",
     "start_time": "2025-06-11T20:47:45.302963Z"
    }
   },
   "outputs": [],
   "source": [
    "type(bs.a.string)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "288066c4",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:47:57.491660Z",
     "start_time": "2025-06-11T20:47:57.473659Z"
    }
   },
   "outputs": [],
   "source": [
    "bs.a.string"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e7e40848",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:48:48.967604Z",
     "start_time": "2025-06-11T20:48:48.957604Z"
    }
   },
   "source": [
    "### 怎么使用"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a9cb948",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:49:54.697364Z",
     "start_time": "2025-06-11T20:49:54.691363Z"
    }
   },
   "source": [
    "#### 文档的遍历"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "419bc1aa",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:51:37.205227Z",
     "start_time": "2025-06-11T20:51:37.178225Z"
    }
   },
   "outputs": [],
   "source": [
    "bs.head.contents"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "89cfc8b2",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:52:21.442757Z",
     "start_time": "2025-06-11T20:52:21.426756Z"
    }
   },
   "outputs": [],
   "source": [
    "bs.head.contents[1]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3b430ece",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:50:09.607217Z",
     "start_time": "2025-06-11T20:50:09.600216Z"
    }
   },
   "source": [
    "#### 文档的搜索"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "87519126",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T21:16:31.704707Z",
     "start_time": "2025-06-11T21:16:31.692707Z"
    }
   },
   "source": [
    "- [ ] find_all()\n",
    "    - [ ] 字符串过滤，会查找与字符串完全匹配的内容\n",
    "    - [ ] 正则表达式搜索：使用search（）方法来匹配内容\n",
    "    - [ ] kwargs 参数查询\n",
    "    - [ ] 文本text查询\n",
    "    - [ ] limit参数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f4894c1c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T21:17:45.037902Z",
     "start_time": "2025-06-11T21:17:45.018901Z"
    }
   },
   "source": [
    "- find_all()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3fb5d03c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T21:12:45.886791Z",
     "start_time": "2025-06-11T21:12:45.868790Z"
    }
   },
   "source": [
    "-  字符串过滤，会查找与字符串完全匹配的内容"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1a6358cc",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 字符串过滤\n",
    "t_list = bs.find_all('a')\n",
    "t_list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "520546f2",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T21:13:16.685553Z",
     "start_time": "2025-06-11T21:13:16.674552Z"
    }
   },
   "source": [
    "- 正则表达式搜索：使用search（）方法来匹配内容"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d910153b",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T08:06:28.309185Z",
     "start_time": "2025-06-12T08:06:28.292185Z"
    }
   },
   "outputs": [],
   "source": [
    "# 正则表达式搜索\n",
    "import re\n",
    "t_list = bs.find_all(re.compile('a'))\n",
    "t_list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0bb36998",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T21:13:45.445198Z",
     "start_time": "2025-06-11T21:13:45.428197Z"
    }
   },
   "source": [
    "- kwargs 参数查询"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "50b981dd",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T07:28:12.353864Z",
     "start_time": "2025-06-12T07:28:12.334863Z"
    }
   },
   "outputs": [],
   "source": [
    "# kwargs 参数查询\n",
    "# t_list = bs.find_all(id='head')\n",
    "t_list = bs.find_all(class_=True)\n",
    "# t_list = bs.find_all(href=\"http://news.baidu.com\")\n",
    "t_list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "840ae53b",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T21:23:13.333679Z",
     "start_time": "2025-06-11T21:23:13.273676Z"
    }
   },
   "source": [
    "- 文本参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7c5a1d88",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T23:25:00.360617Z",
     "start_time": "2025-06-11T23:25:00.338616Z"
    }
   },
   "outputs": [],
   "source": [
    "t_list = bs.find_all(text=\"hao123\")\n",
    "t_list = bs.find_all(text=[\"hao123\", '地图', '贴吧'])\n",
    "t_list = bs.find_all(text=re.compile('\\d'))\n",
    "\n",
    "t_list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fceb8731",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T23:26:41.599408Z",
     "start_time": "2025-06-11T23:26:41.588407Z"
    }
   },
   "source": [
    "- limit参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7882e74c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T23:27:50.830368Z",
     "start_time": "2025-06-11T23:27:50.808366Z"
    }
   },
   "outputs": [],
   "source": [
    "t_list = bs.find_all('a',limit=3) \n",
    "t_list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2351ae5e",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T23:28:55.342057Z",
     "start_time": "2025-06-11T23:28:55.329057Z"
    }
   },
   "source": [
    "## css选择器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "92a6e1d3",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T23:38:20.004354Z",
     "start_time": "2025-06-11T23:38:19.973352Z"
    }
   },
   "outputs": [],
   "source": [
    "# 通过标签查找\n",
    "t_list = bs.select('title')\n",
    "# 通过类名查找\n",
    "t_list = bs.select('.mnav')\n",
    "# 通过id来查找\n",
    "t_list = bs.select('#ul')\n",
    "# 通过属性来查找\n",
    "t_list = bs.select(\"a[class='bri']\")\n",
    "# 通过子标签查找\n",
    "t_list = bs.select(\"head > title\")\n",
    "# 通过兄弟类名查找\n",
    "t_list = bs.select(\".mnav ~ .bri\")\n",
    "\n",
    "\n",
    "\n",
    "t_list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "50444f0b",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T23:39:59.996073Z",
     "start_time": "2025-06-11T23:39:59.990073Z"
    }
   },
   "source": [
    "## 正则表达式"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "748cb813",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T23:40:29.170742Z",
     "start_time": "2025-06-11T23:40:29.164742Z"
    }
   },
   "source": [
    "### 常用操作符"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3ccb2142",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T23:43:25.122806Z",
     "start_time": "2025-06-11T23:43:25.107805Z"
    }
   },
   "source": [
    "| 操作符 | 说明 | 实例 |\n",
    "| :---: | :---: | :---: |\n",
    "| . |表示任何单个字符| |\n",
    "| [ ] |字符集，对单个字符给出取值范围 |[abc]表示a、b、c，[a-z]表示a到z的单个字符 |\n",
    "| [^ ] |非字符集对单个字符给出排除范围 |[^abc]表示非a或b或c的单个字符 |\n",
    "| * |前一个字符0次或无限次扩展 |abc* 表示ab、abc、abcc、abccc等 |\n",
    "| + |前一个字符1次或无限次扩展 |abc+ 表示abc、abcc、abccc等 |\n",
    "| ? |前一个字符0次或1次扩展 |abc? 表示ab、abc |\n",
    "| \\| |左右表达式任意一个 |abc\\|def 表示abc、def |\n",
    "| {m} | 扩展前一个字符m次 | ab{2}c表示abbc |\n",
    "| {m,n} | 扩展前一个字符m至n次（包含n） | ab{1,2}c表示abc、abbc |\n",
    "| ^ | 匹配字符串开头 | ^abc表示abc且在一个字符串的开头 |\n",
    "| \\$ | 匹配字符串结尾 | abc$表示abc且在一个字符串的结尾 |\n",
    "| ( ) | 分组标记，内部只能用\\| | (abc)表示abc，(abc\\|def)表示abc、def |\n",
    "| \\d | 数字等价于[0-9] |  |\n",
    "| \\w | 单词字符，等价于[A-Za-z0-9_] |  |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f2543920",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T05:11:27.444570Z",
     "start_time": "2025-06-12T05:11:27.436570Z"
    }
   },
   "source": [
    "### re库主要功能函数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "128808e8",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T05:11:32.775875Z",
     "start_time": "2025-06-12T05:11:32.761875Z"
    }
   },
   "source": [
    "| 函数 | 说明 |\n",
    "| :---: | :---: |\n",
    "| re.search() | 在一个字符串中搜索匹配正则表达式的第一个位置，返回match对象 | \n",
    "| re.match() | 从一个字符串的开始位置起匹配正则表达式，返回match对象 | \n",
    "| re.findall() | 搜索字符串，以列表类型返回全部能匹配的子串 | \n",
    "| re.split() | 将一个字符串安装正则表达式匹配结果进行分割，返回列表类型 | \n",
    "| re.finditer | 搜索字符串，返回一个匹配结果的迭代类型，每个迭代元素是match对象 | \n",
    "| re.sub() | 在一个字符串中替换所有匹配正则表达式的子串，返回替换后的字符串 | "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51c91ee4",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T05:18:44.836588Z",
     "start_time": "2025-06-12T05:18:44.830587Z"
    }
   },
   "source": [
    "### re修饰符"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d60b322",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T05:24:31.486415Z",
     "start_time": "2025-06-12T05:24:31.466414Z"
    }
   },
   "source": [
    "| 修饰符 | 描述 |\n",
    "| :---: | :---: |\n",
    "| re.l |  使匹配对大小写不敏感 |  \n",
    "| re.L |  做本地化识别（local-aware）匹配 |                  \n",
    "| re.M | 多行匹配，影响^和$ |                  \n",
    "| re.S | 使.匹配包含换行在内的所有字符 |                  \n",
    "| re.U |  根据Unicode字符集解析字符。这个标志影响\\w,\\W,\\b,\\B|\n",
    "| re.X | 给与更灵活的格式以便你讲正则表达式写的更易于理解 |                  "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e45348fc",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T05:38:03.696871Z",
     "start_time": "2025-06-12T05:38:03.684870Z"
    }
   },
   "source": [
    "### 使用"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a71a630f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T06:52:14.295430Z",
     "start_time": "2025-06-12T06:52:14.282430Z"
    }
   },
   "source": [
    "- [ ] search方法匹配\n",
    "    - [ ] 进行比对查找\n",
    "- [ ] findall方法\n",
    "- [ ] sub替换   "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ff8977b4",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T20:56:18.140295Z",
     "start_time": "2025-06-11T20:56:18.123294Z"
    }
   },
   "source": [
    "- search方法匹配<br>\n",
    "  只查询出第一个匹配到的结果就结束查找"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a2bbb536",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T08:02:28.038443Z",
     "start_time": "2025-06-12T08:02:28.024442Z"
    }
   },
   "outputs": [],
   "source": [
    "import re\n",
    "# 创建模式对象\n",
    "pat = re.compile('C.*?A')\n",
    "m = pat.search('CBBACDAAA')\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ff9c075f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T05:44:17.714263Z",
     "start_time": "2025-06-12T05:44:17.699263Z"
    }
   },
   "outputs": [],
   "source": [
    "m = pat.search('AABCAADGGDSAAA')\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c49af3a8",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T05:47:03.020718Z",
     "start_time": "2025-06-12T05:47:03.003717Z"
    }
   },
   "outputs": [],
   "source": [
    "# 没有模式对象\n",
    "m = re.search('abc','ADabc') # 前面的为规则，后面的是校验的对象\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f24ba81f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T05:52:34.062653Z",
     "start_time": "2025-06-12T05:52:34.034651Z"
    }
   },
   "source": [
    "- findall方法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "01dc8628",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T08:23:37.055026Z",
     "start_time": "2025-06-12T08:23:37.043026Z"
    }
   },
   "outputs": [],
   "source": [
    "m = re.findall('C.*?',\"CBBACBBBACBA\") # 查询所有符合的内容，以集合返回\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "14216391",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T05:52:21.453932Z",
     "start_time": "2025-06-12T05:52:21.428930Z"
    }
   },
   "outputs": [],
   "source": [
    "m = re.findall('[A-Z]',\"SDFSaLFdfdAJJFa\") # 查询所有符合的内容，以集合返回\n",
    "m"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ae719820",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T06:48:54.307992Z",
     "start_time": "2025-06-12T06:48:54.293991Z"
    }
   },
   "outputs": [],
   "source": [
    "m = re.findall('[A-Z]+',\"SDFSaLFdfdAJJFa\") # 查询所有符合的内容，以集合返回\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "24f9fc63",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T06:51:29.717881Z",
     "start_time": "2025-06-12T06:51:29.708880Z"
    }
   },
   "source": [
    "- sub<br>\n",
    "替换"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fe59997d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T06:51:00.049184Z",
     "start_time": "2025-06-12T06:51:00.034183Z"
    }
   },
   "outputs": [],
   "source": [
    "m = re.sub('a','A',\"abcdafadfga\") # 从第三个参数找到a用A替换\n",
    "m"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d96ce842",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T06:54:12.890214Z",
     "start_time": "2025-06-12T06:54:12.876213Z"
    }
   },
   "source": [
    "建议在正则表达式中，被比较的字符串前面加上r，不用担心转义字符的问题"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4dffbeac",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T06:56:02.564487Z",
     "start_time": "2025-06-12T06:56:02.550486Z"
    }
   },
   "outputs": [],
   "source": [
    "a = \"\\sfsa-\\' \"\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "68c2b40b",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T06:56:25.906822Z",
     "start_time": "2025-06-12T06:56:25.892821Z"
    }
   },
   "outputs": [],
   "source": [
    "a = r\"\\sfsa-\\' \"\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12306f29",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T07:02:22.335208Z",
     "start_time": "2025-06-12T07:02:22.329208Z"
    }
   },
   "source": [
    "## 开始解析数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f57323b6",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T18:24:35.676462Z",
     "start_time": "2025-06-12T18:24:26.595942Z"
    },
    "code_folding": []
   },
   "outputs": [],
   "source": [
    "# 解析网页,获取数据\n",
    "from bs4 import BeautifulSoup\n",
    "# 正则表达式，进行文字匹配\n",
    "import re\n",
    "# 制定url，获取网页数据\n",
    "import urllib.request, urllib.error\n",
    "# 进行Excel操作\n",
    "import xlwt\n",
    "# 进行SQLite数据库操作\n",
    "import sqlite3\n",
    "\n",
    "\n",
    "# 定义模块get_url，功能：获取网页内容\n",
    "def get_url(url):\n",
    "    # 获取response数据\n",
    "    ## 封装请求：\n",
    "    ### 请求头\n",
    "    headers = {\n",
    "        # 模拟浏览器头部信息，向服务器发送消息\n",
    "        'user-agent':\n",
    "        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'\n",
    "    }\n",
    "    ## 发送请求\n",
    "    req = urllib.request.Request(\n",
    "        url,\n",
    "        headers=headers,\n",
    "    )\n",
    "    ## 获取响应数据\n",
    "    ### 获取数据失败时的异常处理\n",
    "    try:\n",
    "        response = urllib.request.urlopen(req)\n",
    "        ### 解码\n",
    "        html = response.read().decode('utf-8')\n",
    "        # 3.打印结果\n",
    "\n",
    "\n",
    "#         print(html)\n",
    "    except urllib.error.URLError as e:\n",
    "        if hasattr(e, \"code\"):\n",
    "            print(e.code)\n",
    "        if hasattr(e, \"reason\"):\n",
    "            print(e.reason)\n",
    "    return html\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "def main():\n",
    "    ### url地址\n",
    "    baseurl = 'https://movie.douban.com/top250?start='\n",
    "    datalist = get_data(baseurl)\n",
    "    print(len(datalist))\n",
    "\n",
    "\n",
    "# 影片详情链接规则\n",
    "findLink = re.compile(r'<a href=\"(.*?)\"')  # 非贪婪匹配\n",
    "# 影片图片的链接规则\n",
    "findImgSrc = re.compile(r'<img.*src=\"(.*?)\"', re.S)\n",
    "# 影片片名\n",
    "findTitle = re.compile(r'<span class=\"title\">(.*)</span>')\n",
    "# 影片评分\n",
    "findRating = re.compile(\n",
    "    r'<span class=\"rating_num\" property=\"v:average\">(.*)</span>')\n",
    "# 评价人数\n",
    "findJudge = re.compile(r'<span>(\\d*)人评价</span>')\n",
    "# 找到概况\n",
    "findInq = re.compile(r'<p class=\"quote\">.*<span>(.*?)</span>', re.S)\n",
    "# 找到影片相关内容\n",
    "findBd = re.compile(r'<div class=\"bd\">.*?<p>(.*?)</p>', re.S)\n",
    "\n",
    "\n",
    "# 爬取网页\n",
    "def get_data(baseurl):\n",
    "    # 定义列表封装数据\n",
    "    datalist = []\n",
    "    # 循环获取每页数据\n",
    "    for i in range(0, 10):\n",
    "        url = baseurl + str(i * 25)\n",
    "        # 保存获取到的网页源码\n",
    "        html = get_url(url)\n",
    "        # 逐一解析数据 需要用到BeautifulSoup库\n",
    "        soup = BeautifulSoup(html, 'html.parser')\n",
    "        # 文档搜索\n",
    "        for item in soup.find_all('div', class_='item'):\n",
    "            # 保存一部电影的全部信息\n",
    "            data = []\n",
    "            # 正则匹配\n",
    "            item = str(item)\n",
    "            # 影片详情超链接\n",
    "            link = re.findall(findLink, item)[0]\n",
    "            data.append(link)\n",
    "\n",
    "            # 图片链接\n",
    "            imgSrc = re.findall(findImgSrc, item)[0]\n",
    "            data.append(imgSrc)\n",
    "\n",
    "            # 影片名称\n",
    "            titles = re.findall(findTitle, item)\n",
    "            if len(titles) == 2:  # 影片名称为多个时\n",
    "                ctitle = titles[0]\n",
    "                data.append(ctitle)  # 添加中文名\n",
    "                otitle = titles[1].replace(\"/\",\"\")  # 添加英文名\n",
    "                data.append(otitle)\n",
    "            else:\n",
    "                data.append(titles[0])\n",
    "                data.append(\" \")  # 英文名无，则留空\n",
    "\n",
    "            # 评分\n",
    "            rating = re.findall(findRating, item)[0]\n",
    "            data.append(rating)\n",
    "\n",
    "            # 评价人数\n",
    "            judgeNum = re.findall(findJudge, item)[0]\n",
    "            data.append(judgeNum)\n",
    "\n",
    "            # 概述\n",
    "            inq = re.findall(findInq, item)\n",
    "            if len(inq) != 0:\n",
    "                inq = inq[0].replace('. ', '')  # 去掉句号\n",
    "                data.append(inq)\n",
    "            else:\n",
    "                data.append(\" \")  # 留空\n",
    "\n",
    "            #  相关信息\n",
    "            bd = re.findall(findBd, item)[0]\n",
    "            bd = re.sub('<br(\\s*)?/>(\\s*)?', ' ', bd)  # 去掉<br/>\n",
    "            bd = re.sub('/', \" \", bd)  # 去掉/\n",
    "            data.append(bd.strip())  # 去掉空格\n",
    "\n",
    "            # 将处理好的一部电影信息存入datalist\n",
    "            datalist.append(data)\n",
    "\n",
    "    return datalist\n",
    "        \n",
    "if __name__ == '__main__':\n",
    "    main()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b1713303",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T18:04:55.837979Z",
     "start_time": "2025-06-12T18:04:55.787976Z"
    }
   },
   "outputs": [],
   "source": [
    "bd = '''\n",
    "     你好<br  />     sjfosjf \n",
    "'''\n",
    "bd = re.sub('<br(\\s*)?/>(\\s*)?', ' ', bd)\n",
    "bd\n",
    "type(bd)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "772e9175",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T09:02:40.405058Z",
     "start_time": "2025-06-12T09:02:40.388057Z"
    },
    "code_folding": [
     1
    ]
   },
   "outputs": [],
   "source": [
    "s = '''\n",
    "<div class=\"item\">\n",
    "                <div class=\"pic\">\n",
    "                    <em>52</em>\n",
    "                    <a href=\"https://movie.douban.com/subject/27060077/\">\n",
    "                        <img width=\"100\" alt=\"绿皮书\" src=\"https://img2.doubanio.com/view/photo/s_ratio_poster/public/p2531065411.webp\">\n",
    "                    </a>\n",
    "                </div>\n",
    "                <div class=\"info\">\n",
    "                    <div class=\"hd\">\n",
    "                        <a href=\"https://movie.douban.com/subject/27060077/\">\n",
    "                            <span class=\"title\">绿皮书</span>\n",
    "                                    <span class=\"title\">&nbsp;/&nbsp;Green Book</span>\n",
    "                                <span class=\"other\">&nbsp;/&nbsp;绿簿旅友(港)  /  幸福绿皮书(台)</span>\n",
    "                        </a>\n",
    "\n",
    "\n",
    "                            <span class=\"playable\">[可播放]</span>\n",
    "                    </div>\n",
    "                    <div class=\"bd\">\n",
    "                        <p>\n",
    "                            导演: 彼得·法雷里 Peter Farrelly&nbsp;&nbsp;&nbsp;主演: 维果·莫腾森 Viggo Mortensen /...<br>\n",
    "                            2018&nbsp;/&nbsp;美国 中国大陆&nbsp;/&nbsp;剧情 喜剧 传记 音乐\n",
    "                        </p>\n",
    "\n",
    "                        \n",
    "                        <div>\n",
    "                            <span class=\"rating45-t\"></span>\n",
    "                            <span class=\"rating_num\" property=\"v:average\">8.9</span>\n",
    "                            <span property=\"v:best\" content=\"10.0\"></span>\n",
    "                            <span>1826617人评价</span>\n",
    "                        </div>\n",
    "\n",
    "                            <p class=\"quote\">\n",
    "                                <span>去除成见，需要勇气。</span>\n",
    "                            </p>\n",
    "                    </div>\n",
    "                </div>\n",
    "            </div>\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cab1cabd",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T09:20:21.919774Z",
     "start_time": "2025-06-12T09:20:21.905773Z"
    }
   },
   "outputs": [],
   "source": [
    "# 影片图片的链接规则\n",
    "findImgSrc = re.compile(r'<img.*src=\"(.*?)\"',re.S)\n",
    "a =re.findall(findImgSrc,s)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3e891547",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T09:18:25.720127Z",
     "start_time": "2025-06-12T09:18:25.698126Z"
    }
   },
   "outputs": [],
   "source": [
    "# 影片片名\n",
    "findTitle = re.compile(r'<span class=\"title\">(.*)</span>')\n",
    "re.findall(findTitle,s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1ccb1311",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T09:16:24.995222Z",
     "start_time": "2025-06-12T09:16:24.981221Z"
    }
   },
   "outputs": [],
   "source": [
    "# 影片评分\n",
    "findRating = re.compile(r'<span class=\"rating_num\" property=\"v:average\">(.*)</span>')\n",
    "re.findall(findRating,s)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3bf3de8e",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T09:11:19.751763Z",
     "start_time": "2025-06-12T09:11:19.730762Z"
    }
   },
   "outputs": [],
   "source": [
    "# 评价人数\n",
    "findJudge = re.compile(r'<span>(\\d*)人评价</span>')\n",
    "re.findall(findJudge,s)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8b4a0b3c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T09:13:13.935294Z",
     "start_time": "2025-06-12T09:13:13.918293Z"
    }
   },
   "outputs": [],
   "source": [
    "# 找到概况 \n",
    "findInq = re.compile(r'<p class=\"quote\">.*<span>(.*?)</span>',re.S)\n",
    "re.findall(findInq,s)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aa196e12",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T10:27:18.018481Z",
     "start_time": "2025-06-12T10:27:18.003480Z"
    }
   },
   "outputs": [],
   "source": [
    "# 找到影片相关内容\n",
    "findBd = re.compile(r'<div class=\"bd\">.*?<p>(.*?)</p>',re.S)\n",
    "bd = re.findall(findBd,s)\n",
    "type(bd)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "531fde0d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T10:23:24.141104Z",
     "start_time": "2025-06-12T10:23:24.120103Z"
    }
   },
   "outputs": [],
   "source": [
    "bd = re.sub('<br(\\s*)?>(\\s*)?', ' ', str(bd))  # 去掉<br/>\n",
    "bd = re.sub('\\[', \"\",bd)  # 去掉/\n",
    "bd = re.sub('\\]', \"\",bd)  # 去掉/\n",
    "bd = re.sub('/', \"\",bd)  # 去掉/\n",
    "bd.strip()\n",
    "bd"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "10dd3cc9",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T07:08:42.544955Z",
     "start_time": "2025-06-12T07:08:42.531954Z"
    }
   },
   "source": [
    "## __name__ == '__main__'的用法<br>\n",
    "代码执行时\\_\\_name\\_\\_就是\\_\\_main\\_\\_,所以此条件恒成立 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3f16deb9",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-11T07:29:35.351814Z",
     "start_time": "2025-06-11T07:29:35.335813Z"
    }
   },
   "outputs": [],
   "source": [
    "def main():\n",
    "    print(\"这段代码正在作为主程序运行\")\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "651774ed",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T10:56:17.666983Z",
     "start_time": "2025-06-12T10:56:17.651983Z"
    }
   },
   "source": [
    "# 保存到Excel"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1d13dcc1",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T10:56:40.493289Z",
     "start_time": "2025-06-12T10:56:40.483288Z"
    }
   },
   "outputs": [],
   "source": [
    "import xlwt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "243ffdd7",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T11:03:20.491168Z",
     "start_time": "2025-06-12T11:03:20.473167Z"
    }
   },
   "outputs": [],
   "source": [
    "workbook = xlwt.Workbook(encoding=\"utf-8\") #  创建工作簿对象\n",
    "worksheet = workbook.add_sheet('sheet1')   # 创建工作表\n",
    "worksheet.write(0,0,'hello')  # 写入数据，行列 内容\n",
    "workbook.save('./数据/example.xls')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eef5e5f3",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T11:19:16.175830Z",
     "start_time": "2025-06-12T11:19:16.108826Z"
    }
   },
   "outputs": [],
   "source": [
    "workbook = xlwt.Workbook(encoding=\"utf-8\") #  创建工作簿对象\n",
    "worksheet = workbook.add_sheet('sheet1')   # 创建工作表\n",
    "\n",
    "for i in range(0,9):\n",
    "    for j in range(0,i+1):\n",
    "        worksheet.write(i,j, f'{i+1} * {j+1}={(i+1)*(j+1)}')\n",
    "\n",
    "workbook.save('./数据/九九乘法表.xls')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "73951f36",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T15:03:11.232271Z",
     "start_time": "2025-06-12T15:02:58.026516Z"
    }
   },
   "outputs": [],
   "source": [
    "datalist = get_data('https://movie.douban.com/top250?start=')\n",
    "datalist"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7cf42114",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T15:03:56.958886Z",
     "start_time": "2025-06-12T15:03:56.468858Z"
    }
   },
   "outputs": [],
   "source": [
    "savepath = \"./数据/豆瓣Top250.xls\"\n",
    "book = xlwt.Workbook(encoding=\"utf-8\")  #  创建工作簿对象\n",
    "sheet = book.add_sheet('豆瓣Top250', cell_overwrite_ok=True)  # 创建工作表\n",
    "col = ('电影详情链接', '图片链接', '影片中文名 ', '影片外国名 ', '评分 ', '评价数 ', '概况 ', '相关信息')\n",
    "for i in range(0, 8):\n",
    "    sheet.write(0, i, col[i])\n",
    "for i in range(0, 250):\n",
    "    data = datalist[i]\n",
    "    for j in range(0, 8):\n",
    "        sheet.write(i + 1, j, data[j])\n",
    "book.save(savepath)\n",
    "print(\"爬取完毕\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9bb65d32",
   "metadata": {},
   "source": [
    "# 最终代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eb8284a7",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T15:12:52.078493Z",
     "start_time": "2025-06-12T15:12:49.842366Z"
    },
    "code_folding": [
     59,
     70
    ]
   },
   "outputs": [],
   "source": [
    "# 解析网页,获取数据\n",
    "from bs4 import BeautifulSoup\n",
    "# 正则表达式，进行文字匹配\n",
    "import re\n",
    "# 制定url，获取网页数据\n",
    "import urllib.request, urllib.error\n",
    "# 进行Excel操作\n",
    "import xlwt\n",
    "# 进行SQLite数据库操作\n",
    "import sqlite3\n",
    "\n",
    "\n",
    "# 定义模块get_url，功能：获取网页内容\n",
    "def get_url(url):\n",
    "    # 获取response数据\n",
    "    ## 封装请求：\n",
    "    ### 请求头\n",
    "    headers = {\n",
    "        # 模拟浏览器头部信息，向服务器发送消息\n",
    "        'user-agent':\n",
    "        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'\n",
    "    }\n",
    "    ## 发送请求\n",
    "    req = urllib.request.Request(\n",
    "        url,\n",
    "        headers=headers,\n",
    "    )\n",
    "    ## 获取响应数据\n",
    "    ### 获取数据失败时的异常处理\n",
    "    try:\n",
    "        response = urllib.request.urlopen(req)\n",
    "        ### 解码\n",
    "        html = response.read().decode('utf-8')\n",
    "        # 3.打印结果\n",
    "\n",
    "\n",
    "#         print(html)\n",
    "    except urllib.error.URLError as e:\n",
    "        if hasattr(e, \"code\"):\n",
    "            print(e.code)\n",
    "        if hasattr(e, \"reason\"):\n",
    "            print(e.reason)\n",
    "    return html\n",
    "\n",
    "\n",
    "def main():\n",
    "    ### url地址\n",
    "    baseurl = 'https://movie.douban.com/top250?start='\n",
    "    # 获取数据\n",
    "    datalist = get_data(baseurl)\n",
    "    # 保存数据\n",
    "    savepath = \"./数据/豆瓣Top250.xls\"\n",
    "    saveData(savepath)\n",
    "\n",
    "\n",
    "# 影片详情链接规则\n",
    "findLink = re.compile(r'<a href=\"(.*?)\"')  # 非贪婪匹配\n",
    "# 影片图片的链接规则\n",
    "findImgSrc = re.compile(r'<img.*src=\"(.*?)\"', re.S)\n",
    "# 影片片名\n",
    "findTitle = re.compile(r'<span class=\"title\">(.*)</span>')\n",
    "# 影片评分\n",
    "findRating = re.compile(\n",
    "    r'<span class=\"rating_num\" property=\"v:average\">(.*)</span>')\n",
    "# 评价人数\n",
    "findJudge = re.compile(r'<span>(\\d*)人评价</span>')\n",
    "# 找到概况\n",
    "findInq = re.compile(r'<p class=\"quote\">.*<span>(.*?)</span>', re.S)\n",
    "# 找到影片相关内容\n",
    "findBd = re.compile(r'<div class=\"bd\">.*?<p>(.*?)</p>', re.S)\n",
    "\n",
    "\n",
    "# 爬取网页\n",
    "def get_data(baseurl):\n",
    "    # 定义列表封装数据\n",
    "    datalist = []\n",
    "    # 循环获取每页数据\n",
    "    for i in range(0, 1):\n",
    "        url = baseurl + str(i * 25)\n",
    "        # 保存获取到的网页源码\n",
    "        html = get_url(url)\n",
    "        # 逐一解析数据 需要用到BeautifulSoup库\n",
    "        soup = BeautifulSoup(html, 'html.parser')\n",
    "        # 文档搜索\n",
    "        for item in soup.find_all('div', class_='item'):\n",
    "            # 保存一部电影的全部信息\n",
    "            data = []\n",
    "            # 正则匹配\n",
    "            item = str(item)\n",
    "            # 影片详情超链接\n",
    "            link = re.findall(findLink, item)[0]\n",
    "            data.append(link)\n",
    "\n",
    "            # 图片链接\n",
    "            imgSrc = re.findall(findImgSrc, item)[0]\n",
    "            data.append(imgSrc)\n",
    "\n",
    "            # 影片名称\n",
    "            titles = re.findall(findTitle, item)\n",
    "            if len(titles) == 2:  # 影片名称为多个时\n",
    "                ctitle = titles[0]\n",
    "                data.append(ctitle)  # 添加中文名\n",
    "                otitle = titles[1]  # 添加英文名\n",
    "                data.append(otitle)\n",
    "            else:\n",
    "                data.append(titles[0])\n",
    "                data.append(\" \")  # 英文名无，则留空\n",
    "\n",
    "            # 评分\n",
    "            rating = re.findall(findRating, item)\n",
    "            data.append(rating)\n",
    "\n",
    "            # 评价人数\n",
    "            judgeNum = re.findall(findJudge, item)\n",
    "            data.append(judgeNum)\n",
    "\n",
    "            # 概述\n",
    "            inq = re.findall(findInq, item)\n",
    "            if len(inq) != 0:\n",
    "                inq = inq[0].replace('. ', '')  # 去掉句号\n",
    "                data.append(inq)\n",
    "            else:\n",
    "                data.append(\" \")  # 留空\n",
    "\n",
    "            #  相关信息\n",
    "            bd = re.findall(findBd, item)[0]\n",
    "            bd = re.sub('<br(\\s*)?/>(\\s*)?', ' ', bd)  # 去掉<br/>\n",
    "            bd = re.sub('/', \" \", bd)  # 去掉/\n",
    "            data.append(bd.strip())  # 去掉空格\n",
    "\n",
    "            # 将处理好的一部电影信息存入datalist\n",
    "            datalist.append(data)\n",
    "        return datalist\n",
    "\n",
    "\n",
    "# 保存数据\n",
    "def saveData(savepath):\n",
    "    book = xlwt.Workbook(encoding=\"utf-8\")  #  创建工作簿对象\n",
    "    sheet = book.add_sheet('豆瓣Top250', cell_overwrite_ok=True)  # 创建工作表\n",
    "    col = ('电影详情链接', '图片链接', '影片中文名 ', '影片外国名 ', '评分 ', '评价数 ', '概况 ', '相关信息')\n",
    "    for i in range(0, 8):\n",
    "        sheet.write(0, i, col[i])\n",
    "    for i in range(0, 250):\n",
    "        data = datalist[i]\n",
    "        for j in range(0, 8):\n",
    "            sheet.write(i + 1, j, data[j])\n",
    "    book.save(savepath)\n",
    "    print(\"爬取完毕\")\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4388a60",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T15:15:44.998384Z",
     "start_time": "2025-06-12T15:15:44.991383Z"
    }
   },
   "source": [
    "# 保存数据到数据库SQLite"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d12c2700",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T15:17:18.516733Z",
     "start_time": "2025-06-12T15:17:18.500732Z"
    }
   },
   "source": [
    "- [ ] 知识储备\n",
    "- [ ] 保存数据到SQLite"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c6273dfc",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T15:32:32.183992Z",
     "start_time": "2025-06-12T15:32:32.088986Z"
    }
   },
   "source": [
    "## 知识储备"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fd755ed3",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T16:01:43.666171Z",
     "start_time": "2025-06-12T16:01:43.659170Z"
    }
   },
   "source": [
    "### 创建数据库表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4d94ee80",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T16:21:38.302500Z",
     "start_time": "2025-06-12T16:21:38.283499Z"
    }
   },
   "outputs": [],
   "source": [
    "import sqlite3\n",
    "conn = sqlite3.connect('./数据库/test.db') # 打开或创建数据库文件\n",
    "c = conn.cursor() # 获取游标\n",
    "sql = '''\n",
    "    create table company\n",
    "        (id int primary key not null,\n",
    "         name text not null,\n",
    "         age int not null,\n",
    "         address char[50],\n",
    "        salary real);\n",
    "'''\n",
    "c.execute(sql) # 执行sql\n",
    "conn.commit() # 提交数据库操作\n",
    "conn.close()  # 关闭数据库连接"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "56ce1d00",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T17:12:20.620308Z",
     "start_time": "2025-06-13T17:12:20.544304Z"
    }
   },
   "outputs": [],
   "source": [
    "import sqlite3\n",
    "conn = sqlite3.connect('./数据库/douban_movies.db')\n",
    "\n",
    "cursor = conn.cursor() # 获取游标\n",
    "\n",
    "cursor.execute('''\n",
    "CREATE TABLE IF NOT EXISTS movies (\n",
    "id INTEGER PRIMARY KEY AUTOINCREMENT,\n",
    "info_link text,\n",
    "pic_link text,\n",
    "cname varchar,\n",
    "ename varchar,\n",
    "score numeric,\n",
    "rated numeric,\n",
    "introduction text,\n",
    "info text)\n",
    "''')\n",
    "conn.commit() # 提交数据库操作\n",
    "conn.close()  # 关闭数据库连接"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b1dda8a",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T16:06:45.278422Z",
     "start_time": "2025-06-12T16:06:45.272422Z"
    }
   },
   "source": [
    "### 查看数据库表"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "56daa9b5",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T17:12:24.508530Z",
     "start_time": "2025-06-13T17:12:24.486529Z"
    }
   },
   "outputs": [],
   "source": [
    "conn = sqlite3.connect('./数据库/test.db') # 打开或创建数据库文件\n",
    "c = conn.cursor() # 获取游标\n",
    "table_name = 'movies'\n",
    "\n",
    "# 执行sql语句，获取表\n",
    "c.execute(f\"select name from sqlite_master where \\\n",
    "type='table';\")\n",
    "tables = c.fetchall()\n",
    "\n",
    "# 打印所有表\n",
    "for table in tables:\n",
    "    print(table[0])\n",
    "    \n",
    "conn.commit() # 提交数据库操作\n",
    "conn.close()  # 关闭数据库连接\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6c33b19e",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T16:11:34.229949Z",
     "start_time": "2025-06-12T16:11:34.217948Z"
    }
   },
   "source": [
    "### 查看表信息"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "105ad433",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T17:12:39.267374Z",
     "start_time": "2025-06-13T17:12:39.239373Z"
    }
   },
   "outputs": [],
   "source": [
    "import sqlite3\n",
    "\n",
    "conn = sqlite3.connect('./数据库/douban_movies.db')\n",
    "c = conn.cursor() # 获取游标\n",
    "table_name = 'movies'\n",
    "\n",
    "# 执行sql语句，获取表\n",
    "c.execute(f'pragma table_info(\"{table_name}\")')\n",
    "columns = c.fetchall()\n",
    "\n",
    "print(columns)\n",
    "\n",
    "# 提取表头信息\n",
    "headers = [column[1] for column in columns]\n",
    "# 打印结果\n",
    "print(headers)\n",
    "    \n",
    "conn.commit() # 提交数据库操作\n",
    "conn.close()  # 关闭数据库连接\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cf732c53",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T16:23:13.234930Z",
     "start_time": "2025-06-12T16:23:13.224929Z"
    }
   },
   "source": [
    "### 插入数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "82bfdabf",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T16:21:47.583031Z",
     "start_time": "2025-06-12T16:21:47.557029Z"
    }
   },
   "outputs": [],
   "source": [
    "# 连接到 SQLite 数据库\n",
    "conn = sqlite3.connect('./数据库/test.db')\n",
    "\n",
    "# 创建一个游标对象，用于执 行 SQL 语 句\n",
    "cursor = conn.cursor()\n",
    "\n",
    "# 要插入的数据列表\n",
    "employees = [(1, '张三', 25, '成都', 5000.0), (2, '李四', 30, '武汉', 6000.0),\n",
    "             (3, '王五', 35, '上海', 7000.0)]\n",
    "\n",
    "# 使用 executemany 方法批量插入数据\n",
    "insert_query = \"INSERT INTO company (id, name, age, address, salary) \\\n",
    "VALUES (?,?,?,?,?)\"\n",
    "cursor.executemany(insert_query, employees)\n",
    "\n",
    "# 提交更改到数据库\n",
    "conn.commit()\n",
    "# 关闭游标和数据库连接\n",
    "cursor.close()\n",
    "conn.close()\n",
    "print(\"数据插入成功！\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8a9eeb7d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T16:23:31.643983Z",
     "start_time": "2025-06-12T16:23:31.636982Z"
    }
   },
   "source": [
    "### 查询数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4e19e088",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T18:20:06.384059Z",
     "start_time": "2025-06-12T18:20:06.358057Z"
    }
   },
   "outputs": [],
   "source": [
    "import sqlite3\n",
    "# 连 接 到 SQLite 数 据 库\n",
    "conn = sqlite3.connect('./数据库/test.db')\n",
    "cursor = conn.cursor()\n",
    "\n",
    "# 要 查 看 的 表 名  \n",
    "table_name = 'company'\n",
    "\n",
    "# 执 行 pragma table_info 查 询\n",
    "cursor.execute(f'pragma table_info(\"{table_name}\")')\n",
    "columns = cursor.fetchall()\n",
    "# 提取表头信息\n",
    "headers = [column[1] for column in columns]\n",
    "print(headers)\n",
    "\n",
    "# 生成查询语句\n",
    "select_query = f\"SELECT {', '.join(headers)} FROM {table_name}\"\n",
    "\n",
    "print(select_query)\n",
    "\n",
    "# 可 以 执 行 查 询 并 获 取 结 果\n",
    "cursor.execute(select_query)\n",
    "results = cursor.fetchall()\n",
    "for row in results:\n",
    "    print(row)\n",
    "# 关闭连接\n",
    "cursor.close()\n",
    "conn.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0cbfd09e",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T21:45:28.422637Z",
     "start_time": "2025-06-13T21:45:28.301630Z"
    }
   },
   "outputs": [],
   "source": [
    "con = sqlite3.connect('./数据库/douban_movies.db')\n",
    "cur = con.cursor()\n",
    "sql = \"select introduction from movies\"\n",
    "cur.execute(sql)\n",
    "data = cur.fetchall()\n",
    "print(data)\n",
    "text = [item[0] for item in data]\n",
    "cur.close()\n",
    "con.close()\n",
    "text\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b3121009",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-14T17:18:23.047835Z",
     "start_time": "2025-06-14T17:18:23.008833Z"
    }
   },
   "outputs": [],
   "source": [
    "import sqlite3\n",
    "con = sqlite3.connect('./数据库/douban_movies.db')\n",
    "cur = con.cursor()\n",
    "page_sql = f\"select * from movies limit 25 offset 0\"\n",
    "total_sql = f\"select count(*) from movies\"\n",
    "data = cur.execute(page_sql)\n",
    "datalist = [movie for movie in data]\n",
    "data =cur.execute(total_sql)\n",
    "total = [item for item in data]\n",
    "cur.close()\n",
    "con.close()\n",
    "total[0][0]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "418b5770",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T16:46:38.803324Z",
     "start_time": "2025-06-12T16:46:38.797323Z"
    }
   },
   "source": [
    "## 保存数据到sqlite"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1cb9f0fd",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2de36d03",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T18:39:55.485072Z",
     "start_time": "2025-06-12T18:39:44.543446Z"
    }
   },
   "outputs": [],
   "source": [
    "import requests\n",
    "from bs4 import BeautifulSoup\n",
    "import sqlite3\n",
    "\n",
    "# 连接到 SQLite 数据库\n",
    "conn = sqlite3.connect('./数据库/douban_movies.db')\n",
    "cursor = conn.cursor()\n",
    "\n",
    "# 创建电影表\n",
    "cursor.execute('''\n",
    "CREATE TABLE IF NOT EXISTS movies (\n",
    "id INTEGER PRIMARY KEY AUTOINCREMENT,\n",
    "info_link text,\n",
    "pic_link text,\n",
    "cname varchar,\n",
    "ename varchar,\n",
    "score numeric,\n",
    "rated numeric,\n",
    "introduction text,\n",
    "info text)\n",
    "''')\n",
    "\n",
    "# 获取数据\n",
    "datalist = get_data('https://movie.douban.com/top250?start=')\n",
    "for data in datalist:  # 获取一个电影数据\n",
    "    for index in range(len(data)): # 遍历每个电影数据\n",
    "        if index == 4 or index == 5:  # 数字类型的不需要变成str\n",
    "            continue\n",
    "        data[index] = '\"' + data[index] + '\"'  # 其他数据需要加上“”变成str\n",
    "#     print(data)\n",
    "    # sql插入语句\n",
    "    insert_query = f\"INSERT INTO movies \\\n",
    "    (info_link, pic_link, cname, ename,score,rated,introduction,info)\\\n",
    "    VALUES ({','.join(data)})\"\n",
    "\n",
    "    #     print(insert_query)\n",
    "    # 执行sql语句\n",
    "    cursor.execute(insert_query)\n",
    "    # 提交更改\n",
    "    conn.commit()\n",
    "\n",
    "conn.close()\n",
    "print('数据已成功保存到数据库！')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fcb7860f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T17:17:16.388225Z",
     "start_time": "2025-06-13T17:17:16.341222Z"
    }
   },
   "outputs": [],
   "source": [
    "import sqlite3\n",
    "# 连 接 到 SQLite 数 据 库\n",
    "conn = sqlite3.connect('./数据库/douban_movies.db')\n",
    "cursor = conn.cursor()\n",
    "\n",
    "# 要 查 看 的 表 名  \n",
    "table_name = 'movies'\n",
    "\n",
    "# 执 行 pragma table_info 查 询\n",
    "cursor.execute(f'pragma table_info(\"{table_name}\")')\n",
    "columns = cursor.fetchall()\n",
    "# 提取表头信息\n",
    "headers = [column[1] for column in columns]\n",
    "print(headers)\n",
    "\n",
    "# 生成查询语句\n",
    "# select_query = f\"SELECT {', '.join(headers)} FROM {table_name}\"\n",
    "select_query = f\"SELECT * FROM {table_name}\"\n",
    "\n",
    "print(select_query)\n",
    "\n",
    "# 可 以 执 行 查 询 并 获 取 结 果\n",
    "data = cursor.execute(select_query)\n",
    "print(data)\n",
    "\n",
    "# results = cursor.fetchall()\n",
    "datalist = [movie for movie in data]\n",
    "print(datalist)\n",
    "# 关闭连接\n",
    "cursor.close()\n",
    "conn.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "67a2cb6f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T17:01:35.710421Z",
     "start_time": "2025-06-13T17:01:35.690420Z"
    }
   },
   "outputs": [],
   "source": [
    "for start in range(0, 250, 25):\n",
    "    print(start)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "043fce33",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T16:49:13.504172Z",
     "start_time": "2025-06-12T16:49:13.495172Z"
    }
   },
   "source": [
    "## 最终代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1a78f3cd",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T17:17:58.374626Z",
     "start_time": "2025-06-13T17:17:41.891684Z"
    },
    "code_folding": [
     86
    ]
   },
   "outputs": [],
   "source": [
    "# 解析网页,获取数据\n",
    "from bs4 import BeautifulSoup\n",
    "# 正则表达式，进行文字匹配\n",
    "import re\n",
    "# 制定url，获取网页数据\n",
    "import urllib.request, urllib.error\n",
    "# 进行Excel操作\n",
    "import xlwt\n",
    "# 进行SQLite数据库操作\n",
    "import sqlite3\n",
    "\n",
    "\n",
    "def main():\n",
    "    # 豆瓣电影 Top250 的 URL\n",
    "    base_url = 'https://movie.douban.com/top250'\n",
    "    # 获取数据\n",
    "    datalist = get_data(base_url)\n",
    "    print(datalist)\n",
    "    # 保存数据\n",
    "    #   savepath = \"./数据/豆瓣Top250.xls\"\n",
    "    #   saveData(savepath)\n",
    "    dbpath = \"./数据库/douban_movies.db\"\n",
    "    saveData2DB(datalist, dbpath)\n",
    "\n",
    "\n",
    "# 影片详情链接规则\n",
    "findLink = re.compile(r'<a href=\"(.*?)\"')  # 非贪婪匹配\n",
    "# 影片图片的链接规则\n",
    "findImgSrc = re.compile(r'<img.*src=\"(.*?)\"', re.S)\n",
    "# 影片片名\n",
    "findTitle = re.compile(r'<span class=\"title\">(.*)</span>')\n",
    "# 影片评分\n",
    "findRating = re.compile(\n",
    "    r'<span class=\"rating_num\" property=\"v:average\">(.*)</span>')\n",
    "# 评价人数\n",
    "findJudge = re.compile(r'<span>(\\d*)人评价</span>')\n",
    "# 找到概况\n",
    "findInq = re.compile(r'<p class=\"quote\">.*<span>(.*?)</span>', re.S)\n",
    "# 找到影片相关内容\n",
    "findBd = re.compile(r'<div class=\"bd\">.*?<p>(.*?)</p>', re.S)\n",
    "\n",
    "\n",
    "# 定义模块get_url，功能：获取网页内容\n",
    "def get_url(url):\n",
    "    # 获取response数据\n",
    "    ## 封装请求：\n",
    "    ### 请求头\n",
    "    headers = {\n",
    "        # 模拟浏览器头部信息，向服务器发送消息\n",
    "        'user-agent':\n",
    "        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'\n",
    "    }\n",
    "    ## 发送请求\n",
    "    req = urllib.request.Request(\n",
    "        url,\n",
    "        headers=headers,\n",
    "    )\n",
    "    ## 获取响应数据\n",
    "    ### 获取数据失败时的异常处理\n",
    "    try:\n",
    "        response = urllib.request.urlopen(req)\n",
    "        ### 解码\n",
    "        html = response.read().decode('utf-8')\n",
    "        # 3.打印结果\n",
    "\n",
    "#         print(html)\n",
    "    except urllib.error.URLError as e:\n",
    "        if hasattr(e, \"code\"):\n",
    "            print(e.code)\n",
    "        if hasattr(e, \"reason\"):\n",
    "            print(e.reason)\n",
    "    return html\n",
    "\n",
    "\n",
    "# 爬取网页\n",
    "def get_data(base_url):\n",
    "    # 定义列表封装数据\n",
    "    datalist = []\n",
    "    # 循环获取每页数据\n",
    "    # 遍历每页\n",
    "    for start in range(0, 250, 25):\n",
    "        url = f'{base_url}?start={start}'\n",
    "        # 保存获取到的网页源码\n",
    "        html = get_url(url)\n",
    "        # 逐一解析数据 需要用到BeautifulSoup库\n",
    "        soup = BeautifulSoup(html, 'html.parser')\n",
    "        # 文档搜索\n",
    "        for item in soup.find_all('div', class_='item'):\n",
    "            # 保存一部电影的全部信息\n",
    "            data = []\n",
    "            # 正则匹配\n",
    "            item = str(item)\n",
    "            # 影片详情超链接\n",
    "            link = re.findall(findLink, item)[0]\n",
    "            data.append(link)\n",
    "\n",
    "            # 图片链接\n",
    "            imgSrc = re.findall(findImgSrc, item)[0]\n",
    "            data.append(imgSrc)\n",
    "\n",
    "            # 影片名称\n",
    "            titles = re.findall(findTitle, item)\n",
    "            if len(titles) == 2:  # 影片名称为多个时\n",
    "                ctitle = titles[0]\n",
    "                data.append(ctitle)  # 添加中文名\n",
    "                otitle = titles[1]  # 添加英文名\n",
    "                data.append(otitle)\n",
    "            else:\n",
    "                data.append(titles[0])\n",
    "                data.append(\" \")  # 英文名无，则留空\n",
    "\n",
    "            # 评分\n",
    "            rating = re.findall(findRating, item)[0]\n",
    "            data.append(rating)\n",
    "\n",
    "            # 评价人数\n",
    "            judgeNum = re.findall(findJudge, item)[0]\n",
    "            data.append(judgeNum)\n",
    "\n",
    "            # 概述\n",
    "            inq = re.findall(findInq, item)\n",
    "            if len(inq) != 0:\n",
    "                inq = inq[0].replace('. ', '')  # 去掉句号\n",
    "                data.append(inq)\n",
    "            else:\n",
    "                data.append(\" \")  # 留空\n",
    "\n",
    "            #  相关信息\n",
    "            bd = re.findall(findBd, item)[0]\n",
    "            bd = re.sub('<br(\\s*)?/>(\\s*)?', ' ', bd)  # 去掉<br/>\n",
    "            bd = re.sub('/', \" \", bd)  # 去掉/\n",
    "            data.append(bd.strip())  # 去掉空格\n",
    "\n",
    "            # 将处理好的一部电影信息存入datalist\n",
    "            datalist.append(data)\n",
    "    return datalist\n",
    "\n",
    "\n",
    "# 保存数据\n",
    "def saveData(savepath):\n",
    "    book = xlwt.Workbook(encoding=\"utf-8\")  #  创建工作簿对象\n",
    "    sheet = book.add_sheet('豆瓣Top250', cell_overwrite_ok=True)  # 创建工作表\n",
    "    col = ('电影详情链接', '图片链接', '影片中文名 ', '影片外国名 ', '评分 ', '评价数 ', '概况 ', '相关信息')\n",
    "    for i in range(0, 8):\n",
    "        sheet.write(0, i, col[i])\n",
    "    for i in range(0, 250):\n",
    "        data = datalist[i]\n",
    "        for j in range(0, 8):\n",
    "            sheet.write(i + 1, j, data[j])\n",
    "    book.save(savepath)\n",
    "    print(\"爬取完毕\")\n",
    "\n",
    "\n",
    "def saveData2DB(datalist, dbpath):\n",
    "    init_db(dbpath)\n",
    "    # 连接到 SQLite 数据库\n",
    "    conn = sqlite3.connect(dbpath)\n",
    "    cursor = conn.cursor()\n",
    "\n",
    "    # 获取每一个电影数据\n",
    "    for data in datalist:\n",
    "        # 遍历每个电影数据\n",
    "        for index in range(len(data)):\n",
    "            # 数字类型的不需要变成str\n",
    "            if index == 4 or index == 5:\n",
    "                continue\n",
    "            # 其他数据需要加上“”变成str\n",
    "            data[index] = '\"' + data[index] + '\"'\n",
    "\n",
    "        # sql插入语句\n",
    "        insert_query = f\"INSERT INTO movies \\\n",
    "            (info_link, pic_link, cname, ename,score,rated,introduction,info)\\\n",
    "            VALUES ({','.join(data)})\"\n",
    "\n",
    "        #     print(insert_query)\n",
    "\n",
    "        # 执行sql语句\n",
    "        cursor.execute(insert_query)\n",
    "        # 提交更改\n",
    "        conn.commit()\n",
    "\n",
    "    # 关闭连接\n",
    "    conn.close()\n",
    "    print('数据已成功保存到数据库！')\n",
    "\n",
    "\n",
    "# 初始化数据库\n",
    "def init_db(dbpath):\n",
    "    # 连接到 SQLite 数据库\n",
    "    conn = sqlite3.connect(dbpath)\n",
    "    cursor = conn.cursor()\n",
    "\n",
    "    # 创建电影表\n",
    "    cursor.execute('''\n",
    "    CREATE TABLE IF NOT EXISTS movies (\n",
    "    id INTEGER PRIMARY KEY AUTOINCREMENT,\n",
    "    info_link text,\n",
    "    pic_link text,\n",
    "    cname varchar,\n",
    "    ename varchar,\n",
    "    score numeric,\n",
    "    rated numeric,\n",
    "    introduction text,\n",
    "    info text)\n",
    "    ''')\n",
    "    # 提交更改并关闭\n",
    "    conn.commit()\n",
    "    conn.close()\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    main()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ef3b1e7",
   "metadata": {},
   "source": [
    "## 代码运行指南\n",
    "- [ ] 安装相应的模块\n",
    "- [ ] 创建相应的路径文件或修改路径"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9dc079f1",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T09:51:09.379239Z",
     "start_time": "2025-06-13T09:51:09.342237Z"
    }
   },
   "source": [
    "'''\n",
    "    # 在激活环境中使用命令  \n",
    "    # 安装bs4  \n",
    "    pip install beautifulsoup4 -i https://pypi.tuna.tsinghua.edu.cn/simple  \n",
    "    # 安装xlwt  \n",
    "    pip install xlwt -i https://pypi.tuna.tsinghua.edu.cn/simple\n",
    "    \n",
    " '''"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e2e518d8",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-12T18:47:32.644220Z",
     "start_time": "2025-06-12T18:47:32.633219Z"
    }
   },
   "source": [
    "# 数据可视化"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb8f7363",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T03:44:31.268019Z",
     "start_time": "2025-06-13T03:44:31.188015Z"
    }
   },
   "source": [
    "- [ ] 知识储备\n",
    "- [ ] 数据可视化"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "01607fe8",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T03:44:44.876798Z",
     "start_time": "2025-06-13T03:44:44.867797Z"
    }
   },
   "source": [
    "## 知识储备"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c798ed0d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T03:45:09.459204Z",
     "start_time": "2025-06-13T03:45:09.450203Z"
    }
   },
   "source": [
    "### flask框架"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "88a27e9a",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T10:12:42.842221Z",
     "start_time": "2025-06-13T10:12:42.825220Z"
    }
   },
   "source": [
    "- [ ] 安装"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "704b3380",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T10:14:31.894459Z",
     "start_time": "2025-06-13T10:14:31.874458Z"
    }
   },
   "source": [
    "```\n",
    "    # conda激活环境下的cmd窗口安装  \n",
    "    pip install flask -i https://pypi.tuna.tsinghua.edu.cn/simple\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a8e71400",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T10:16:22.258771Z",
     "start_time": "2025-06-13T10:16:22.243770Z"
    }
   },
   "source": [
    "- [ ] 使用"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9d119426",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T10:23:26.434033Z",
     "start_time": "2025-06-13T10:23:26.414032Z"
    }
   },
   "source": [
    " 框架结构：\n",
    " - Excel爬虫\n",
    "  - static\n",
    "  - templates\n",
    "  - 豆瓣电影top数据可视化.py  \n",
    "  \n",
    "在项目目录下，是没有static目录和templates目录的，因此需要我们自己去创建一下"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "546e03d7",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T10:56:24.997200Z",
     "start_time": "2025-06-13T10:55:47.129034Z"
    },
    "code_folding": []
   },
   "outputs": [],
   "source": [
    "from flask import Flask\n",
    "    \n",
    "app = Flask(__name__)\n",
    "\n",
    "@app.route('/')\n",
    "def hello_world():\n",
    "    return 'hello world!'\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d622375c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T10:56:45.076348Z",
     "start_time": "2025-06-13T10:56:25.040202Z"
    }
   },
   "outputs": [],
   "source": [
    "from flask import Flask\n",
    "    \n",
    "app = Flask(__name__)\n",
    "\n",
    "@app.route('/index')\n",
    "def hello_world():\n",
    "    return '你好'\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5cdead99",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T10:57:23.062521Z",
     "start_time": "2025-06-13T10:57:23.048520Z"
    }
   },
   "source": [
    "#### 获取路径参数"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c5eb06cf",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-14T19:48:56.050493Z",
     "start_time": "2025-06-14T19:48:56.029492Z"
    }
   },
   "source": [
    "- [ ] 通过过访问路径获取字符串参数\n",
    "- [ ] 获取整型参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "fe6feefe",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T10:59:07.916518Z",
     "start_time": "2025-06-13T10:58:47.942376Z"
    }
   },
   "outputs": [],
   "source": [
    "from flask import Flask\n",
    "    \n",
    "app = Flask(__name__)\n",
    "\n",
    "# 通过过访问路径获取用户的字符串参数\n",
    "@app.route('/user/<name>')\n",
    "def hello_world(name):\n",
    "    return f'你好,{name}'\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ce3dc0c0",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T11:04:29.599918Z",
     "start_time": "2025-06-13T11:02:45.652972Z"
    }
   },
   "outputs": [],
   "source": [
    "from flask import Flask\n",
    "    \n",
    "app = Flask(__name__)\n",
    "\n",
    "# 通过过访问路径获取整型参数\n",
    "@app.route('/user/<int:id>')\n",
    "def hello_world(id):\n",
    "    return f'你好,{id}号会员'\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "545d728f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T11:07:09.791080Z",
     "start_time": "2025-06-13T11:07:09.780079Z"
    }
   },
   "source": [
    "#### 解析html文件render_template\n",
    "- [x] 解析html\n",
    "- [ ] 向页面传递变量\n",
    "    - [ ] 普通变量\n",
    "    - [ ] 列表\n",
    "    - [ ] 字典\n",
    "- [ ] 表单提交"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29efe944",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T13:40:24.211971Z",
     "start_time": "2025-06-13T13:40:20.755773Z"
    }
   },
   "source": [
    "- 通过过访问路径获取整型参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d3c7e3f2",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T13:33:25.300011Z",
     "start_time": "2025-06-13T13:09:36.229272Z"
    }
   },
   "outputs": [],
   "source": [
    "from flask import Flask,render_template\n",
    "    \n",
    "app = Flask(__name__)\n",
    "\n",
    "# 通过过访问路径获取整型参数\n",
    "@app.route('/')\n",
    "def index():\n",
    "    return render_template(\"index.html\")\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d9e4d6c0",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T13:55:34.863057Z",
     "start_time": "2025-06-13T13:55:34.843056Z"
    }
   },
   "source": [
    "index.html代码为\n",
    "```\n",
    "    <!DOCTYPE html>\n",
    "    <html lang=\"en\">\n",
    "    <head>\n",
    "        <meta charset=\"utf-8\">\n",
    "        <title>Title</title>\n",
    "    </head>\n",
    "    <body>\n",
    "        hello，大家好\n",
    "    </body>\n",
    "    </html>\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3cba5738",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T14:00:59.801643Z",
     "start_time": "2025-06-13T14:00:59.762640Z"
    }
   },
   "source": [
    "- [ ] 解析html\n",
    "- [ ] 向页面传递变量\n",
    "    - [x] 普通变量\n",
    "    - [ ] 列表\n",
    "    - [ ] 字典\n",
    "- [ ] 表单提交"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d2be4c0e",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T13:37:04.393542Z",
     "start_time": "2025-06-13T13:36:38.098038Z"
    }
   },
   "outputs": [],
   "source": [
    "from flask import Flask,render_template\n",
    "import datetime\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "# 通过过访问路径获取整型参数\n",
    "@app.route('/')\n",
    "def index():\n",
    "    time = datetime.date.today()\n",
    "    return render_template(\"index.html\",var = time)\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "605748df",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T13:59:49.322611Z",
     "start_time": "2025-06-13T13:59:49.300610Z"
    }
   },
   "source": [
    "index.html代码为\n",
    "```\n",
    "    <!DOCTYPE html>\n",
    "    <html lang=\"en\">\n",
    "    <head>\n",
    "        <meta charset=\"utf-8\">\n",
    "        <title>Title</title>\n",
    "    </head>\n",
    "    <body>\n",
    "        hello，大家好,今天是{{ var }}。\n",
    "    </body>\n",
    "    </html>\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ef3e6414",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T14:00:59.801643Z",
     "start_time": "2025-06-13T14:00:59.762640Z"
    }
   },
   "source": [
    "- [ ] 解析html\n",
    "- [ ] 向页面传递变量\n",
    "    - [ ] 普通变量\n",
    "    - [x] 列表\n",
    "    - [ ] 字典\n",
    "- [ ] 表单提交"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "14db6a64",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T13:54:19.700758Z",
     "start_time": "2025-06-13T13:53:02.006314Z"
    }
   },
   "outputs": [],
   "source": [
    "from flask import Flask,render_template\n",
    "import datetime\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "# 通过过访问路径获取整型参数\n",
    "@app.route('/')\n",
    "def index():\n",
    "    time = datetime.date.today()\n",
    "    name = ['荒','韩老魔','叶凡','不良帅']\n",
    "    return render_template(\"index.html\",var = time,list = name)\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "df45fccc",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T14:00:06.412589Z",
     "start_time": "2025-06-13T14:00:06.386587Z"
    }
   },
   "source": [
    "index.html代码为\n",
    "```\n",
    "<!DOCTYPE html>\n",
    "<html lang=\"en\">\n",
    "<head>\n",
    "\t<meta charset=\"utf-8\">\n",
    "\t<title>Title</title>\n",
    "</head>\n",
    "<body>\n",
    "\thello，大家好,今天是{{ var }}。\n",
    "\t今天出场人物是：<br/>\n",
    "\t{% for data in list %}\n",
    "\t\t<li> {{data}} </li>\n",
    "\t{% endfor %}\n",
    "</body>\n",
    "</html>\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cd427b66",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T14:00:59.801643Z",
     "start_time": "2025-06-13T14:00:59.762640Z"
    }
   },
   "source": [
    "- [ ] 解析html\n",
    "- [ ] 向页面传递变量\n",
    "    - [ ] 普通变量\n",
    "    - [ ] 列表\n",
    "    - [x] 字典\n",
    "- [ ] 表单提交"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "43ae9892",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T14:19:16.802387Z",
     "start_time": "2025-06-13T14:14:38.705481Z"
    }
   },
   "outputs": [],
   "source": [
    "from flask import Flask,render_template\n",
    "import datetime\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "# 通过过访问路径获取整型参数\n",
    "@app.route('/')\n",
    "def index():\n",
    "    time = datetime.date.today()\n",
    "    name = ['荒','韩老魔','叶凡','李星云']\n",
    "    task = {'完美世界': '荒','凡人修仙传':'韩老魔','遮天':'叶凡',\n",
    "            '不良帅':'李星云'} # 字典\n",
    "    return render_template(\"index.html\",var = time,list = name,task= task)\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e177b39f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T14:02:25.038518Z",
     "start_time": "2025-06-13T14:02:25.004516Z"
    }
   },
   "source": [
    "index.html代码为\n",
    "```\n",
    "    <!DOCTYPE html>\n",
    "    <html lang=\"en\">\n",
    "    <head>\n",
    "        <meta charset=\"utf-8\">\n",
    "        <title>Title</title>\n",
    "    </head>\n",
    "    <body>\n",
    "        hello，大家好,今天是{{ var }}。\n",
    "        今天出场人物是：<br/>\n",
    "        {% for data in list %}\n",
    "            <li> {{data}} </li>\n",
    "        {% endfor %}\n",
    "\n",
    "        追漫：<br/>\n",
    "        <table border='1'>\n",
    "            {% for key,value in task.items() %}\n",
    "                <tr>\n",
    "                    <td>{{key}}</td>\n",
    "                    <td>{{value}}</td>\n",
    "                </tr>\n",
    "            {% endfor %}\n",
    "\n",
    "        </table>\n",
    "    </body>\n",
    "    </html>\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7d91c28d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T14:00:59.801643Z",
     "start_time": "2025-06-13T14:00:59.762640Z"
    }
   },
   "source": [
    "- [ ] 解析html\n",
    "- [ ] 向页面传递变量\n",
    "    - [ ] 普通变量\n",
    "    - [ ] 列表\n",
    "    - [ ] 字典\n",
    "- [x] 表单提交"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b0464cbc",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T15:30:55.937284Z",
     "start_time": "2025-06-13T15:05:45.978919Z"
    }
   },
   "outputs": [],
   "source": [
    "from flask import Flask,render_template,request\n",
    "import datetime\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "# 表单提交\n",
    "@app.route('/test/register')\n",
    "def register():\n",
    "   \n",
    "    return render_template(\"test/register.html\")\n",
    "\n",
    "# 接收表单提交的路由，需要指定methods为post\n",
    "@app.route('/result',methods=['post','get'])\n",
    "def result():\n",
    "    if request.method == 'POST':  # 必须大写\n",
    "        result = request.form\n",
    "        print(result)\n",
    "    return render_template(\"test/result.html\",result=result)\n",
    "\n",
    "\n",
    "\n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0329efcd",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T14:02:25.038518Z",
     "start_time": "2025-06-13T14:02:25.004516Z"
    }
   },
   "source": [
    "register.html代码为\n",
    "```\n",
    "<!DOCTYPE html>\n",
    "<html lang=\"en\">\n",
    "<head>\n",
    "\t<meta charset=\"utf-8\">\n",
    "\t<title>Title</title>\n",
    "</head>\n",
    "<body>\n",
    "\t<form action='http://localhost:5000/result' method='post'>\n",
    "\t\t<p> 姓名： <input type='text' name='姓名'> </p>\n",
    "\t\t<p> 年龄： <input type='text' name='年龄'> </p>\n",
    "\t\t<p> 性别：<input type='text' name='性别'> </p>\n",
    "\t\t<p> 地址： <input type='text' name='地址'> </p>\n",
    "\t\t<p>  <input type='submit' value='提交'> </p>\n",
    "\t\t\n",
    "\t</form>\n",
    "</body>\n",
    "</html>\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4abd2401",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T14:02:25.038518Z",
     "start_time": "2025-06-13T14:02:25.004516Z"
    }
   },
   "source": [
    "result.html代码为\n",
    "```\n",
    "<!DOCTYPE html>\n",
    "<html lang=\"en\">\n",
    "<head>\n",
    "\t<meta charset=\"utf-8\">\n",
    "\t<title>Title</title>\n",
    "</head>\n",
    "<body>\n",
    "\t<table border='1'>\n",
    "\t\t{% for key,value in result.items() %}\n",
    "\t\t\t<tr>\n",
    "\t\t\t\t<th>{{key}}</th>\n",
    "\t\t\t\t<td>{{value}}</td>\n",
    "\t\t\t</tr>\n",
    "\t\t{% endfor %}\n",
    "\t\t\n",
    "\t</table>\n",
    "</body>\n",
    "</html>\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b48f704",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T14:19:17.136407Z",
     "start_time": "2025-06-13T14:19:17.097404Z"
    }
   },
   "source": [
    "- [ ] 解析html\n",
    "- [ ] 向页面传递变量\n",
    "    - [ ] 普通变量\n",
    "- [ ] 表单提交\n",
    "    - [x] 动态路由url_for"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "23ea7a73",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T14:02:25.038518Z",
     "start_time": "2025-06-13T14:02:25.004516Z"
    }
   },
   "source": [
    "register.html代码为\n",
    "```\n",
    "<!DOCTYPE html>\n",
    "<html lang=\"en\">\n",
    "<head>\n",
    "\t<meta charset=\"utf-8\">\n",
    "\t<title>Title</title>\n",
    "</head>\n",
    "<body>\n",
    "\t<form action='{{ url_for('result') }}' method='post'>\n",
    "\t\t<p> 姓名： <input type='text' name='姓名'> </p>\n",
    "\t\t<p> 年龄： <input type='text' name='年龄'> </p>\n",
    "\t\t<p> 性别：<input type='text' name='性别'> </p>\n",
    "\t\t<p> 地址： <input type='text' name='地址'> </p>\n",
    "\t\t<p>  <input type='submit' value='提交'> </p>\n",
    "\t\t\n",
    "\t</form>\n",
    "</body>\n",
    "</html>\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7a0b9813",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T15:30:55.978286Z",
     "start_time": "2025-06-13T15:30:55.965286Z"
    }
   },
   "source": [
    "## 数据可视化"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f3745bbd",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T15:30:56.030289Z",
     "start_time": "2025-06-13T15:30:56.016288Z"
    }
   },
   "source": [
    "### 首页制作\n",
    "这里需要前端模板，需自行下载"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39c6aba5",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T17:49:12.988848Z",
     "start_time": "2025-06-13T17:24:21.889562Z"
    }
   },
   "outputs": [],
   "source": [
    "from flask import Flask,render_template,request\n",
    "import sqlite3\n",
    "\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "# 表单提交\n",
    "@app.route('/')\n",
    "def index():\n",
    "    return render_template(\"index.html\")\n",
    "\n",
    "@app.route('/index')\n",
    "def home():\n",
    "    return index()\n",
    "\n",
    "@app.route('/movie')\n",
    "def movie():\n",
    "    datalist = []\n",
    "    con = sqlite3.connect('./数据库/douban_movies.db')\n",
    "    cur = con.cursor()\n",
    "    sql = \"select * from movies\"\n",
    "    data = cur.execute(sql)\n",
    "    datalist = [movie for movie in data]\n",
    "    cur.close()\n",
    "    con.close()\n",
    "    return render_template(\"movie.html\",movies = datalist)\n",
    "\n",
    "@app.route('/score')\n",
    "def score():\n",
    "    return render_template(\"score.html\")\n",
    "\n",
    "@app.route('/word')\n",
    "def word():\n",
    "    return render_template(\"word.html\")\n",
    "\n",
    "@app.route('/team')\n",
    "def team():\n",
    "    return render_template(\"team.html\")\n",
    "\n",
    "\n",
    "    \n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "50c1263c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T17:49:32.177946Z",
     "start_time": "2025-06-13T17:49:32.155944Z"
    }
   },
   "source": [
    "### echarts的使用"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cc3911db",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T17:50:45.076115Z",
     "start_time": "2025-06-13T17:50:45.066115Z"
    }
   },
   "source": [
    "#### 使用：下载js文件并引入"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "029f70fd",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T18:46:42.762164Z",
     "start_time": "2025-06-13T18:46:42.736162Z"
    }
   },
   "source": [
    "score.html\n",
    "```\n",
    "\n",
    "  <!DOCTYPE html>\n",
    "<html lang=\"en\">\n",
    "\n",
    "<head>\n",
    "  <meta charset=\"utf-8\">\n",
    "  <meta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\">\n",
    "  <!-- 引入刚刚下载的 ECharts 文件 -->\n",
    "  <script src=\"static/assets/js/echarts.min.js\"></script>\n",
    "  <title>豆瓣Top250数据可视化</title>\n",
    "  <meta content=\"\" name=\"descriptison\">\n",
    "  <meta content=\"\" name=\"keywords\">\n",
    "\t\n",
    "  <!-- Favicons -->\n",
    "  <link href=\"static/assets/img/favicon.png\" rel=\"icon\">\n",
    "  <link href=\"static/assets/img/apple-touch-icon.png\" rel=\"apple-touch-icon\">\n",
    "\n",
    "  <!-- Google Fonts -->\n",
    "  <link href=\"https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i|Raleway:300,300i,400,400i,600,600i,700,700i,900\" rel=\"stylesheet\">\n",
    "\n",
    "  <!-- Vendor CSS Files -->\n",
    "  <link href=\"static/assets/vendor/bootstrap/css/bootstrap.min.css\" rel=\"stylesheet\">\n",
    "  <link href=\"static/assets/vendor/icofont/icofont.min.css\" rel=\"stylesheet\">\n",
    "  <link href=\"static/assets/vendor/boxicons/css/boxicons.min.css\" rel=\"stylesheet\">\n",
    "  <link href=\"static/assets/vendor/animate.css/animate.min.css\" rel=\"stylesheet\">\n",
    "  <link href=\"static/assets/vendor/venobox/venobox.css\" rel=\"stylesheet\">\n",
    "  <link href=\"static/assets/vendor/aos/aos.css\" rel=\"stylesheet\">\n",
    "\n",
    "  <!-- Template Main CSS File -->\n",
    "  <link href=\"static/assets/css/style.css\" rel=\"stylesheet\">\n",
    "\n",
    "</head>\n",
    "\n",
    "<body>\n",
    "\n",
    "\n",
    " \n",
    "\n",
    "  <!-- ======= Header ======= -->\n",
    "  <header id=\"header\">\n",
    "    <div class=\"container\">\n",
    "\n",
    "      <div class=\"logo float-left\">\n",
    "        <h1 class=\"text-light\"><a href=\"index.html\"><span>Mamba</span></a></h1>\n",
    "        <!-- Uncomment below if you prefer to use an image logo -->\n",
    "        <!-- <a href=\"index.html\"><img src=\"static/assets/img/logo.png\" alt=\"\" class=\"img-fluid\"></a>-->\n",
    "      </div>\n",
    "\n",
    "      <nav class=\"nav-menu float-right d-none d-lg-block\">\n",
    "        <ul>\n",
    "          <li class=\"active\"><a href=\"/index\">首页 <i class=\"la la-angle-down\"></i></a></li>\n",
    "          <li><a href=\"/movie\">电影</a></li>\n",
    "          <li><a href=\"/score\">评分</a></li>\n",
    "          <li><a href=\"/word\">词云</a></li>\n",
    "          <li><a href=\"/team\">团队</a></li>\n",
    "         \n",
    "        </ul>\n",
    "      </nav><!-- .nav-menu -->\n",
    "\n",
    "    </div>\n",
    "  </header><!-- End Header -->\n",
    "\n",
    "   <!-- ======= Our Team Section ======= -->\n",
    "    <section id=\"team\" class=\"team\">\n",
    "      <div class=\"container\">\n",
    "\n",
    "        <div class=\"section-title\">\n",
    "          <h2>豆瓣电影Top250评分分布图</h2>\n",
    "        </div>\n",
    "\t\t\n",
    "      </div>\n",
    "\t </section>\n",
    "\t \n",
    "\t            <!-- ======= Counts Section ======= -->\n",
    "    <section class=\"counts section-bg\">\n",
    "       <!-- 为 ECharts 准备一个定义了宽高的 DOM -->\n",
    "    <div id=\"main\" style=\"width: 90%;height:300px;\"></div>\n",
    "\t \n",
    "    </section><!-- End Counts Section -->\n",
    "\t\n",
    "\t\n",
    "\t\n",
    "\t <script type=\"text/javascript\">\n",
    "\t\tvar dom = document.getElementById('main');\n",
    "\t\tvar myChart = echarts.init(dom, null, {\n",
    "\t\t  renderer: 'canvas',\n",
    "\t\t  useDirtyRect: false\n",
    "\t\t});\n",
    "\t\tvar app = {};\n",
    "\t\t\n",
    "\t\tvar option;\n",
    "\n",
    "\t\toption = {\n",
    "\t  color:['#D8BFD8'],\n",
    "\t  tooltip:{\n",
    "\t\ttrigger: 'axis',\n",
    "\t\taxisPointer:{\n",
    "\t\t  type:'shadow'\n",
    "\t\t}\n",
    "\t  },\n",
    "\t  grid:{\n",
    "\t\tleft:'5%',\n",
    "\t\tright:'5%',\n",
    "\t\tbottom:'3%',\n",
    "\t\tcontainLabel:true\n",
    "\t\t\n",
    "\t  },\n",
    "\t  xAxis: {\n",
    "\t\ttype: 'category',\n",
    "\t\tdata: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n",
    "\t  },\n",
    "\t  yAxis: {\n",
    "\t\ttype: 'value'\n",
    "\t  },\n",
    "\t  series: [\n",
    "\t\t{\n",
    "\t\t  data: [120, 200, 150, 80, 70, 110, 130],\n",
    "\t\t  type: 'bar'\n",
    "\t\t}\n",
    "\t  ]\n",
    "\t};\n",
    "\n",
    "\t\tif (option && typeof option === 'object') {\n",
    "\t\t  myChart.setOption(option);\n",
    "\t\t}\n",
    "\n",
    "\t\twindow.addEventListener('resize', myChart.resize);\n",
    "  </script>\n",
    "       \n",
    "        \n",
    "   \n",
    "\n",
    " \n",
    "  <!-- ======= Footer ======= -->\n",
    "  <footer id=\"footer\">\n",
    "    \n",
    "    <div class=\"container\">\n",
    "      <div class=\"copyright\">Copyright &copy; 2020.Company name All rights reserved.\n",
    "      <div class=\"credits\"></div>\n",
    "    </div>\n",
    "  </footer><!-- End Footer -->\n",
    "\n",
    "  <a href=\"#\" class=\"back-to-top\"><i class=\"icofont-simple-up\"></i></a>\n",
    "\n",
    "  <!-- Vendor JS Files -->\n",
    "  <script src=\"static/assets/vendor/jquery/jquery.min.js\"></script>\n",
    "  <script src=\"static/assets/vendor/bootstrap/js/bootstrap.bundle.min.js\"></script>\n",
    "  <script src=\"static/assets/vendor/jquery.easing/jquery.easing.min.js\"></script>\n",
    "  <script src=\"static/assets/vendor/php-email-form/validate.js\"></script>\n",
    "  <script src=\"static/assets/vendor/jquery-sticky/jquery.sticky.js\"></script>\n",
    "  <script src=\"static/assets/vendor/venobox/venobox.min.js\"></script>\n",
    "  <script src=\"static/assets/vendor/waypoints/jquery.waypoints.min.js\"></script>\n",
    "  <script src=\"static/assets/vendor/counterup/counterup.min.js\"></script>\n",
    "  <script src=\"static/assets/vendor/isotope-layout/isotope.pkgd.min.js\"></script>\n",
    "  <script src=\"static/assets/vendor/aos/aos.js\"></script>\n",
    "\n",
    "  <!-- Template Main JS File -->\n",
    "  <script src=\"static/assets/js/main.js\"></script>\n",
    "\n",
    "</body>\n",
    "\n",
    "</html>\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c3ab151c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T19:22:43.130730Z",
     "start_time": "2025-06-13T19:22:43.116729Z"
    }
   },
   "source": [
    "### 连接数据库获取评分数据，并添加到echarts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7901bba3",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T20:28:26.751292Z",
     "start_time": "2025-06-13T19:34:31.209230Z"
    }
   },
   "outputs": [],
   "source": [
    "from flask import Flask,render_template,request\n",
    "import sqlite3\n",
    "\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "# 表单提交\n",
    "@app.route('/')\n",
    "def index():\n",
    "    return render_template(\"index.html\")\n",
    "\n",
    "@app.route('/index')\n",
    "def home():\n",
    "    return index()\n",
    "\n",
    "@app.route('/movie')\n",
    "def movie():\n",
    "    con = sqlite3.connect('./数据库/douban_movies.db')\n",
    "    cur = con.cursor()\n",
    "    sql = \"select * from movies\"\n",
    "    data = cur.execute(sql)\n",
    "    datalist = [movie for movie in data]\n",
    "    cur.close()\n",
    "    con.close()\n",
    "    return render_template(\"movie.html\",movies = datalist)\n",
    "\n",
    "@app.route('/score')\n",
    "def score():\n",
    "    con = sqlite3.connect('./数据库/douban_movies.db')\n",
    "    cur = con.cursor()\n",
    "    sql = \"select score,count(score) from movies group by score\"\n",
    "    cur.execute(sql)\n",
    "    data = cur.fetchall()\n",
    "    score = [item[0] for item in data]\n",
    "    num = [item[1] for item in data]\n",
    "    cur.close()\n",
    "    con.close()\n",
    "    \n",
    "    return render_template(\"score.html\",score=score,num=num)\n",
    "\n",
    "@app.route('/word')\n",
    "def word():\n",
    "    return render_template(\"word.html\")\n",
    "\n",
    "@app.route('/team')\n",
    "def team():\n",
    "    return render_template(\"team.html\")\n",
    "\n",
    "    \n",
    "    \n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "60da7a92",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-13T20:28:26.773293Z",
     "start_time": "2025-06-13T20:28:26.762293Z"
    }
   },
   "source": [
    "### 词云的使用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "15d99f5f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-14T16:09:53.108760Z",
     "start_time": "2025-06-14T16:09:35.781769Z"
    }
   },
   "outputs": [],
   "source": [
    "import jieba\n",
    "from matplotlib import pyplot as plt\n",
    "from wordcloud import WordCloud\n",
    "from PIL import Image\n",
    "import numpy as np\n",
    "import sqlite3\n",
    "\n",
    "# 查询数据库\n",
    "con = sqlite3.connect('./数据库/douban_movies.db')\n",
    "cur = con.cursor()\n",
    "sql = \"select introduction from movies\"\n",
    "cur.execute(sql)\n",
    "data = cur.fetchall() \n",
    "text =  ''.join(item[0] for item in data)\n",
    "str(text)\n",
    "\n",
    "cur.close()\n",
    "con.close()\n",
    "# 分词\n",
    "cut = \" \".join(jieba.cut(text))\n",
    "\n",
    "#\n",
    "img = Image.open(r'./static/assets/img/300.jpg')\n",
    "img_arry = np.array(img) #将图片转换为数组\n",
    "\n",
    "#词云\n",
    "wc = WordCloud(\n",
    "    background_color='white',\n",
    "    mask=img_arry,\n",
    "    font_path=\"msyhbd.ttf\"\n",
    ")\n",
    "wc.generate_from_text(cut)\n",
    "\n",
    "#绘制图片\n",
    "fig = plt.figure(1)\n",
    "plt.imshow(wc)\n",
    "plt.axis(\"off\")\n",
    "\n",
    "# 展示图片\n",
    "#plt.show()\n",
    "\n",
    "# 保存图片\n",
    "plt.savefig(r'./static/assets/img/word.jpg',dpi=500)\n",
    "len(cut)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "51026c78",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-14T16:09:09.251251Z",
     "start_time": "2025-06-14T16:09:09.175247Z"
    }
   },
   "source": [
    "word.html\n",
    "```\n",
    " <!DOCTYPE html>\n",
    "<html lang=\"en\">\n",
    "\n",
    "<head>\n",
    "  <meta charset=\"utf-8\">\n",
    "  <meta content=\"width=device-width, initial-scale=1.0\" name=\"viewport\">\n",
    "\n",
    "  <title>豆瓣Top250数据可视化</title>\n",
    "  <meta content=\"\" name=\"descriptison\">\n",
    "  <meta content=\"\" name=\"keywords\">\n",
    "\n",
    "  <!-- Favicons -->\n",
    "  <link href=\"static/assets/img/favicon.png\" rel=\"icon\">\n",
    "  <link href=\"static/assets/img/apple-touch-icon.png\" rel=\"apple-touch-icon\">\n",
    "\n",
    "  <!-- Google Fonts -->\n",
    "  <link href=\"https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i|Raleway:300,300i,400,400i,600,600i,700,700i,900\" rel=\"stylesheet\">\n",
    "\n",
    "  <!-- Vendor CSS Files -->\n",
    "  <link href=\"static/assets/vendor/bootstrap/css/bootstrap.min.css\" rel=\"stylesheet\">\n",
    "  <link href=\"static/assets/vendor/icofont/icofont.min.css\" rel=\"stylesheet\">\n",
    "  <link href=\"static/assets/vendor/boxicons/css/boxicons.min.css\" rel=\"stylesheet\">\n",
    "  <link href=\"static/assets/vendor/animate.css/animate.min.css\" rel=\"stylesheet\">\n",
    "  <link href=\"static/assets/vendor/venobox/venobox.css\" rel=\"stylesheet\">\n",
    "  <link href=\"static/assets/vendor/aos/aos.css\" rel=\"stylesheet\">\n",
    "\n",
    "  <!-- Template Main CSS File -->\n",
    "  <link href=\"static/assets/css/style.css\" rel=\"stylesheet\">\n",
    "\n",
    "</head>\n",
    "\n",
    "<body>\n",
    "\n",
    "\n",
    " \n",
    "\n",
    "  <!-- ======= Header ======= -->\n",
    "  <header id=\"header\">\n",
    "    <div class=\"container\">\n",
    "\n",
    "      <div class=\"logo float-left\">\n",
    "        <h1 class=\"text-light\"><a href=\"index.html\"><span>Mamba</span></a></h1>\n",
    "        <!-- Uncomment below if you prefer to use an image logo -->\n",
    "        <!-- <a href=\"index.html\"><img src=\"static/assets/img/logo.png\" alt=\"\" class=\"img-fluid\"></a>-->\n",
    "      </div>\n",
    "\n",
    "      <nav class=\"nav-menu float-right d-none d-lg-block\">\n",
    "        <ul>\n",
    "          <li class=\"active\"><a href=\"/index\">首页 <i class=\"la la-angle-down\"></i></a></li>\n",
    "          <li><a href=\"/movie\">电影</a></li>\n",
    "          <li><a href=\"/score\">评分</a></li>\n",
    "          <li><a href=\"/word\">词云</a></li>\n",
    "          <li><a href=\"/team\">团队</a></li>\n",
    "         \n",
    "        </ul>\n",
    "      </nav><!-- .nav-menu -->\n",
    "\n",
    "    </div>\n",
    "  </header><!-- End Header -->\n",
    "\n",
    "   <!-- ======= About Us Section ======= -->\n",
    "    <section id=\"about\" class=\"about\">\n",
    "      <div class=\"container\">\n",
    "\n",
    "        <div class=\"row no-gutters\">\n",
    "          <div class=\"col-lg-6 video-box\">\n",
    "            <img src=\"static/assets/img/word.jpg\" class=\"img-fluid\" alt=\"\">\n",
    "            \n",
    "\t\t  </div>\n",
    "\n",
    "          <div class=\"col-lg-6 d-flex flex-column justify-content-center about-content\">\n",
    "\n",
    "            <div class=\"section-title\">\n",
    "              <h2>词云统计</h2>\n",
    "              <p>‌根据250电影的概述，提炼出词云，从这些词中也许可以让我们有不一样的体悟并且从中获取的生活的启发，<br>\n",
    "\t\t\t\t或许可以更深层地参悟生活的某些意义。\n",
    "\t\t\t  </p>\n",
    "            </div>\n",
    "\t\t\t\n",
    "\t\t\t<div class=\"icon-box\" data-aos=\"fade-up\" data-aos-delay=\"100\">\n",
    "              <div class=\"icon\"><i class=\"bx bx-fingerprint\"></i></div>\n",
    "              <h4 class=\"title\"><a href=\"\">关于电影</a></h4>\n",
    "              <p class=\"description\">也许你在某一瞬间，顿悟到了什么</p>\n",
    "            </div>\n",
    "            \n",
    "\n",
    "          </div>\n",
    "        </div>\n",
    "\n",
    "      </div>\n",
    "    </section><!-- End About Us Section -->\n",
    "\n",
    " \n",
    "  <!-- ======= Footer ======= -->\n",
    "  <footer id=\"footer\">\n",
    "    \n",
    "    <div class=\"container\">\n",
    "      <div class=\"copyright\">Copyright &copy; 2020.Company name All rights reserved.\n",
    "      <div class=\"credits\"></div>\n",
    "    </div>\n",
    "  </footer><!-- End Footer -->\n",
    "\n",
    "  <a href=\"#\" class=\"back-to-top\"><i class=\"icofont-simple-up\"></i></a>\n",
    "\n",
    "  <!-- Vendor JS Files -->\n",
    "  <script src=\"static/assets/vendor/jquery/jquery.min.js\"></script>\n",
    "  <script src=\"static/assets/vendor/bootstrap/js/bootstrap.bundle.min.js\"></script>\n",
    "  <script src=\"static/assets/vendor/jquery.easing/jquery.easing.min.js\"></script>\n",
    "  <script src=\"static/assets/vendor/php-email-form/validate.js\"></script>\n",
    "  <script src=\"static/assets/vendor/jquery-sticky/jquery.sticky.js\"></script>\n",
    "  <script src=\"static/assets/vendor/venobox/venobox.min.js\"></script>\n",
    "  <script src=\"static/assets/vendor/waypoints/jquery.waypoints.min.js\"></script>\n",
    "  <script src=\"static/assets/vendor/counterup/counterup.min.js\"></script>\n",
    "  <script src=\"static/assets/vendor/isotope-layout/isotope.pkgd.min.js\"></script>\n",
    "  <script src=\"static/assets/vendor/aos/aos.js\"></script>\n",
    "\n",
    "  <!-- Template Main JS File -->\n",
    "  <script src=\"static/assets/js/main.js\"></script>\n",
    "\n",
    "</body>\n",
    "\n",
    "</html>   \n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "44c76298",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-14T16:49:07.417419Z",
     "start_time": "2025-06-14T16:11:21.909839Z"
    }
   },
   "outputs": [],
   "source": [
    "from flask import Flask,render_template,request\n",
    "import sqlite3\n",
    "\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "# 表单提交\n",
    "@app.route('/')\n",
    "def index():\n",
    "    return render_template(\"index.html\")\n",
    "\n",
    "@app.route('/index')\n",
    "def home():\n",
    "    return index()\n",
    "\n",
    "@app.route('/movie')\n",
    "def movie():\n",
    "    con = sqlite3.connect('./数据库/douban_movies.db')\n",
    "    cur = con.cursor()\n",
    "    sql = \"select * from movies\"\n",
    "    data = cur.execute(sql)\n",
    "    datalist = [movie for movie in data]\n",
    "    cur.close()\n",
    "    con.close()\n",
    "    return render_template(\"movie.html\",movies = datalist)\n",
    "\n",
    "@app.route('/score')\n",
    "def score():\n",
    "    con = sqlite3.connect('./数据库/douban_movies.db')\n",
    "    cur = con.cursor()\n",
    "    sql = \"select score,count(score) from movies group by score\"\n",
    "    cur.execute(sql)\n",
    "    data = cur.fetchall()\n",
    "    score = [item[0] for item in data]\n",
    "    num = [item[1] for item in data]\n",
    "    cur.close()\n",
    "    con.close()\n",
    "    \n",
    "    return render_template(\"score.html\",score=score,num=num)\n",
    "\n",
    "@app.route('/word')\n",
    "def word():\n",
    "    return render_template(\"word.html\")\n",
    "\n",
    "@app.route('/team')\n",
    "def team():\n",
    "    return render_template(\"team.html\")\n",
    "\n",
    "    \n",
    "    \n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fbc700dc",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-14T16:11:14.610421Z",
     "start_time": "2025-06-14T16:11:14.599421Z"
    }
   },
   "source": [
    "# 项目优化"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "76cbcaf4",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-14T16:49:07.452421Z",
     "start_time": "2025-06-14T16:49:07.437420Z"
    }
   },
   "source": [
    "## 电影分页"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f92823c5",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-14T16:49:14.536826Z",
     "start_time": "2025-06-14T16:49:14.516825Z"
    }
   },
   "source": [
    "安装分页插件\n",
    "```\n",
    " pip install flask-paginate -i https://pypi.tuna.tsinghua.edu.cn/simple\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "76c0799a",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-14T16:49:19.668119Z",
     "start_time": "2025-06-14T16:49:19.655119Z"
    }
   },
   "outputs": [],
   "source": [
    "from flask_paginate import Pagination,get_page_args"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b5aed953",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-15T14:11:15.948975Z",
     "start_time": "2025-06-15T14:03:44.277141Z"
    }
   },
   "outputs": [],
   "source": [
    "from flask import Flask,render_template,request,session\n",
    "import sqlite3\n",
    "from flask_paginate import Pagination,get_page_args\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "# 存储每页展示的数据条数\n",
    "app.config['PER_PAGE'] = 20\n",
    "\n",
    "\n",
    "@app.route('/movie', methods=['POST','GET'])\n",
    "def movie():\n",
    "    # 获取分页数据，   默认值为  page = 1  per_page = 10\n",
    "    page,per_page,offset=get_page_args(get_page_parameter='page',get_per_page_parameter='per_page')\n",
    "    \n",
    "    per_page = app.config['PER_PAGE']\n",
    "    offset = (page - 1) * per_page\n",
    "    \n",
    "    if request.method == 'POST':\n",
    "        temp = request.form['per_page']\n",
    "        # 更新数据\n",
    "        app.config['PER_PAGE'] = int(temp)\n",
    "        per_page = int(temp)\n",
    "        page = 1\n",
    "        \n",
    "    # 连接数据库\n",
    "    con = sqlite3.connect(\"./数据库/douban_movies.db\")\n",
    "    cur = con.cursor()\n",
    "    \n",
    "    pages_sql = f'select * from movies limit {per_page } offset {offset }'\n",
    "    total_sql = f'select count(*) from movies' \n",
    "    print(pages_sql)\n",
    "    \n",
    "    data = cur.execute(pages_sql)\n",
    "    movies_list = [movie for movie in data]\n",
    "    \n",
    "    cur.execute(total_sql)\n",
    "    total = cur.fetchall()[0][0]\n",
    "        \n",
    "    \n",
    "    cur.close()\n",
    "    con.close()\n",
    "    pagination = Pagination(page=page,per_page=per_page,total=total)\n",
    "    \n",
    "    return render_template('movie.html',movies = movies_list,pagination = pagination,per_page = per_page,page=page)\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "# 表单提交\n",
    "@app.route('/')\n",
    "def index():\n",
    "    return render_template(\"index.html\")\n",
    "\n",
    "@app.route('/index')\n",
    "def home():\n",
    "    return index()\n",
    "\n",
    "@app.route('/score')\n",
    "def score():\n",
    "    return render_template(\"score.html\")\n",
    "\n",
    "@app.route('/word')\n",
    "def word():\n",
    "    return render_template(\"word.html\")\n",
    "\n",
    "@app.route('/team')\n",
    "def team():\n",
    "    return render_template(\"team.html\")\n",
    "\n",
    "\n",
    "    \n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8dad8797",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-15T14:11:15.972976Z",
     "start_time": "2025-06-15T14:11:15.960976Z"
    }
   },
   "source": [
    "# 迭代代码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "70db2ba1",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-06-15T14:14:32.913241Z",
     "start_time": "2025-06-15T14:11:15.984977Z"
    }
   },
   "outputs": [],
   "source": [
    "from flask import Flask,render_template,request\n",
    "import sqlite3\n",
    "\n",
    "\n",
    "app = Flask(__name__)\n",
    "\n",
    "# 表单提交\n",
    "@app.route('/')\n",
    "def index():\n",
    "    return render_template(\"index.html\")\n",
    "\n",
    "@app.route('/index')\n",
    "def home():\n",
    "    return index()\n",
    "\n",
    "# 存储每页展示的数据条数\n",
    "app.config['PER_PAGE'] = 20\n",
    "\n",
    "\n",
    "@app.route('/movie', methods=['POST','GET'])\n",
    "def movie():\n",
    "    # 获取分页数据，   默认值为  page = 1  per_page = 10\n",
    "    page,per_page,offset=get_page_args(get_page_parameter='page',get_per_page_parameter='per_page')\n",
    "    \n",
    "    per_page = app.config['PER_PAGE']\n",
    "    offset = (page - 1) * per_page\n",
    "    \n",
    "    if request.method == 'POST':\n",
    "        temp = request.form['per_page']\n",
    "        # 更新数据\n",
    "        app.config['PER_PAGE'] = int(temp)\n",
    "        per_page = int(temp)\n",
    "        page = 1\n",
    "        \n",
    "    # 连接数据库\n",
    "    con = sqlite3.connect(\"./数据库/douban_movies.db\")\n",
    "    cur = con.cursor()\n",
    "    \n",
    "    pages_sql = f'select * from movies limit {per_page } offset {offset }'\n",
    "    total_sql = f'select count(*) from movies' \n",
    "    print(pages_sql)\n",
    "    \n",
    "    data = cur.execute(pages_sql)\n",
    "    movies_list = [movie for movie in data]\n",
    "    \n",
    "    cur.execute(total_sql)\n",
    "    total = cur.fetchall()[0][0]\n",
    "        \n",
    "    \n",
    "    cur.close()\n",
    "    con.close()\n",
    "    pagination = Pagination(page=page,per_page=per_page,total=total)\n",
    "    \n",
    "    return render_template('movie.html',movies = movies_list,pagination = pagination,per_page = per_page,page=page)\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "@app.route('/score')\n",
    "def score():\n",
    "    con = sqlite3.connect('./数据库/douban_movies.db')\n",
    "    cur = con.cursor()\n",
    "    sql = \"select score,count(score) from movies group by score\"\n",
    "    cur.execute(sql)\n",
    "    data = cur.fetchall()\n",
    "    score = [item[0] for item in data]\n",
    "    num = [item[1] for item in data]\n",
    "    cur.close()\n",
    "    con.close()\n",
    "    \n",
    "    return render_template(\"score.html\",score=score,num=num)\n",
    "\n",
    "@app.route('/word')\n",
    "def word():\n",
    "    return render_template(\"word.html\")\n",
    "\n",
    "@app.route('/team')\n",
    "def team():\n",
    "    return render_template(\"team.html\")\n",
    "\n",
    "    \n",
    "    \n",
    "if __name__ == '__main__':\n",
    "    app.run()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4433b743",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "env1",
   "language": "python",
   "name": "env1"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.20"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "244.5px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
